<commit_before>import json
import logging

from django.contrib import messages
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.http.response import HttpResponseServerError
from django.shortcuts import render, get_object_or_404
from django.utils.decorators import method_decorator
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _, ugettext_noop, ugettext_lazy
from django.views.decorators.http import require_http_methods

from couchdbkit import ResourceNotFound, BulkSaveError
from corehq.apps.style.decorators import (
    use_jquery_ui,
    use_multiselect,
)
from corehq.util.files import file_extention_from_filename
from couchexport.models import Format
from dimagi.utils.decorators.memoized import memoized
from dimagi.utils.web import json_response
from soil.exceptions import TaskFailedError
from soil.util import expose_cached_download, get_download_context

from corehq import toggles
from corehq.apps.commtrack.tasks import import_locations_async, location_lock_key, LOCK_LOCATIONS_TIMEOUT
from corehq.apps.commtrack.util import unicode_slug
from corehq.apps.consumption.shortcuts import get_default_monthly_consumption
from corehq.apps.custom_data_fields import CustomDataModelMixin
from corehq.apps.domain.decorators import domain_admin_required
from corehq.apps.domain.views import BaseDomainView
from corehq.apps.hqwebapp.utils import get_bulk_upload_form
from corehq.apps.products.models import Product, SQLProduct
from corehq.apps.users.decorators import require_can_edit_commcare_users
from corehq.apps.users.forms import MultipleSelectionForm
from corehq.apps.locations.permissions import location_safe
from corehq.util import reverse
from dimagi.utils.couch import release_lock
from dimagi.utils.couch.cache.cache_core import get_redis_client

from .analytics import users_have_locations
from .const import ROOT_LOCATION_TYPE
from .dbaccessors import get_users_assigned_to_locations
from .exceptions import LocationConsistencyError
from .permissions import (
    locations_access_required,
    is_locations_admin,
    can_edit_location,
    can_edit_location_types,
    user_can_edit_any_location,
    can_edit_any_location,
)
from .models import Location, LocationType, SQLLocation, filter_for_archived
from .forms import LocationForm, UsersAtLocationForm
from .tree_utils import assert_no_cycles
from .util import load_locs_json, location_hierarchy_config, dump_locations


logger = logging.getLogger(__name__)


@locations_access_required
def default(request, domain):
    return HttpResponseRedirect(reverse(LocationsListView.urlname, args=[domain]))


def lock_locations(func):
    # Decorate a post/delete method of a view to ensure concurrent locations edits don't happen.
    def func_wrapper(request, *args, **kwargs):
        key = location_lock_key(request.domain)
        client = get_redis_client()
        lock = client.lock(key, LOCK_LOCATIONS_TIMEOUT)
        if lock.acquire(blocking=False):
            try:
                return func(request, *args, **kwargs)
            finally:
                release_lock(lock, True)
        else:
            message = _("Some of the location edits are still in progress, "
                        "please wait until they finish and then try again")
            messages.warning(request, message)
            if request.method == 'DELETE':
                # handle delete_location view
                return json_response({'success': False, 'message': message})
            else:
                return HttpResponseRedirect(request.META['HTTP_REFERER'])

    return func_wrapper


class BaseLocationView(BaseDomainView):
    section_name = ugettext_lazy("Locations")

    @method_decorator(locations_access_required)
    def dispatch(self, request, *args, **kwargs):
        return super(BaseLocationView, self).dispatch(request, *args, **kwargs)

    @property
    def can_access_all_locations(self):
        return self.request.couch_user.has_permission(self.domain, 'access_all_locations')

    @property
    def section_url(self):
        return reverse(LocationsListView.urlname, args=[self.domain])

    @property
    def main_context(self):
        context = super(BaseLocationView, self).main_context
        context.update({
            'hierarchy': location_hierarchy_config(self.domain),
            'api_root': reverse('api_dispatch_list', kwargs={'domain': self.domain,
                                                             'resource_name': 'location_internal',
                                                             'api_name': 'v0.5'}),
        })
        return context


@location_safe
class LocationsListView(BaseLocationView):
    urlname = 'manage_locations'
    page_title = ugettext_noop("Organization Structure")
    template_name = 'locations/manage/locations.html'

    @use_jquery_ui
    @method_decorator(require_can_edit_commcare_users)
    def dispatch(self, request, *args, **kwargs):
        return super(LocationsListView, self).dispatch(request, *args, **kwargs)

    @property
    def show_inactive(self):
        return json.loads(self.request.GET.get('show_inactive', 'false'))

    @property
    def can_edit_root(self):
        # once permissions are unified, this need only be can_access_all_locations
        loc_restricted = self.request.project.location_restriction_for_users
        return self.can_access_all_locations and (
            not loc_restricted
            or (loc_restricted and not self.request.couch_user.get_location(self.domain))
        )

    @property
    def page_context(self):
        has_location_types = len(self.domain_object.location_types) > 0
        return {
            'locations': self.get_visible_locations(),
            'show_inactive': self.show_inactive,
            'has_location_types': has_location_types,
            'can_edit_root': self.can_edit_root,
            'can_edit_any_location': user_can_edit_any_location(self.request.couch_user, self.request.project),
        }

    def get_visible_locations(self):
        def to_json(loc):
            return {<commit_msg>Switch couch location usage to sql location<commit_after>import json
import logging

from django.contrib import messages
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.http.response import HttpResponseServerError
from django.shortcuts import render, get_object_or_404
from django.utils.decorators import method_decorator
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _, ugettext_noop, ugettext_lazy
from django.views.decorators.http import require_http_methods

from couchdbkit import ResourceNotFound, BulkSaveError
from corehq.apps.style.decorators import (
    use_jquery_ui,
    use_multiselect,
)
from corehq.util.files import file_extention_from_filename
from couchexport.models import Format
from dimagi.utils.decorators.memoized import memoized
from dimagi.utils.web import json_response
from soil.exceptions import TaskFailedError
from soil.util import expose_cached_download, get_download_context

from corehq import toggles
from corehq.apps.commtrack.tasks import import_locations_async, location_lock_key, LOCK_LOCATIONS_TIMEOUT
from corehq.apps.commtrack.util import unicode_slug
from corehq.apps.consumption.shortcuts import get_default_monthly_consumption
from corehq.apps.custom_data_fields import CustomDataModelMixin
from corehq.apps.domain.decorators import domain_admin_required
from corehq.apps.domain.views import BaseDomainView
from corehq.apps.hqwebapp.utils import get_bulk_upload_form
from corehq.apps.products.models import Product, SQLProduct
from corehq.apps.users.decorators import require_can_edit_commcare_users
from corehq.apps.users.forms import MultipleSelectionForm
from corehq.apps.locations.permissions import location_safe
from corehq.util import reverse
from dimagi.utils.couch import release_lock
from dimagi.utils.couch.cache.cache_core import get_redis_client

from .analytics import users_have_locations
from .const import ROOT_LOCATION_TYPE
from .dbaccessors import get_users_assigned_to_locations
from .exceptions import LocationConsistencyError
from .permissions import (
    locations_access_required,
    is_locations_admin,
    can_edit_location,
    can_edit_location_types,
    user_can_edit_any_location,
    can_edit_any_location,
)
from .models import Location, LocationType, SQLLocation, filter_for_archived
from .forms import LocationForm, UsersAtLocationForm
from .tree_utils import assert_no_cycles
from .util import load_locs_json, location_hierarchy_config, dump_locations


logger = logging.getLogger(__name__)


@locations_access_required
def default(request, domain):
    return HttpResponseRedirect(reverse(LocationsListView.urlname, args=[domain]))


def lock_locations(func):
    # Decorate a post/delete method of a view to ensure concurrent locations edits don't happen.
    def func_wrapper(request, *args, **kwargs):
        key = location_lock_key(request.domain)
        client = get_redis_client()
        lock = client.lock(key, LOCK_LOCATIONS_TIMEOUT)
        if lock.acquire(blocking=False):
            try:
                return func(request, *args, **kwargs)
            finally:
                release_lock(lock, True)
        else:
            message = _("Some of the location edits are still in progress, "
                        "please wait until they finish and then try again")
            messages.warning(request, message)
            if request.method == 'DELETE':
                # handle delete_location view
                return json_response({'success': False, 'message': message})
            else:
                return HttpResponseRedirect(request.META['HTTP_REFERER'])

    return func_wrapper


class BaseLocationView(BaseDomainView):
    section_name = ugettext_lazy("Locations")

    @method_decorator(locations_access_required)
    def dispatch(self, request, *args, **kwargs):
        return super(BaseLocationView, self).dispatch(request, *args, **kwargs)

    @property
    def can_access_all_locations(self):
        return self.request.couch_user.has_permission(self.domain, 'access_all_locations')

    @property
    def section_url(self):
        return reverse(LocationsListView.urlname, args=[self.domain])

    @property
    def main_context(self):
        context = super(BaseLocationView, self).main_context
        context.update({
            'hierarchy': location_hierarchy_config(self.domain),
            'api_root': reverse('api_dispatch_list', kwargs={'domain': self.domain,
                                                             'resource_name': 'location_internal',
                                                             'api_name': 'v0.5'}),
        })
        return context


@location_safe
class LocationsListView(BaseLocationView):
    urlname = 'manage_locations'
    page_title = ugettext_noop("Organization Structure")
    template_name = 'locations/manage/locations.html'

    @use_jquery_ui
    @method_decorator(require_can_edit_commcare_users)
    def dispatch(self, request, *args, **kwargs):
        return super(LocationsListView, self).dispatch(request, *args, **kwargs)

    @property
    def show_inactive(self):
        return json.loads(self.request.GET.get('show_inactive', 'false'))

    @property
    def can_edit_root(self):
        # once permissions are unified, this need only be can_access_all_locations
        loc_restricted = self.request.project.location_restriction_for_users
        return self.can_access_all_locations and (
            not loc_restricted
            or (loc_restricted and not self.request.couch_user.get_sql_location(self.domain))
        )

    @property
    def page_context(self):
        has_location_types = len(self.domain_object.location_types) > 0
        return {
            'locations': self.get_visible_locations(),
            'show_inactive': self.show_inactive,
            'has_location_types': has_location_types,
            'can_edit_root': self.can_edit_root,
            'can_edit_any_location': user_can_edit_any_location(self.request.couch_user, self.request.project),
        }

    def get_visible_locations(self):
        def to_json(loc):
            return {
{'fraction_non_alphanumeric': 0.07223035627135188, 'fraction_numerical': 0.0014641288433382138, 'mean_word_length': 3.730665640631012, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6176227', 'n_tokens_mistral': 3521, 'n_tokens_neox': 3392, 'n_words': 790}