<commit_before>import re

from django import forms
from django.template import Context
from django.template.loader import get_template
from django.utils.translation import ugettext as _

from crispy_forms.helper import FormHelper
from crispy_forms import layout as crispy
from dimagi.utils.couch.database import iter_docs
from dimagi.utils.decorators.memoized import memoized

from corehq.apps.custom_data_fields import CustomDataEditor
from corehq.apps.es import UserES
from corehq.apps.users.forms import MultipleSelectionForm
from corehq.apps.users.models import CommCareUser
from corehq.apps.users.util import raw_username, user_display_string

from .models import Location
from .signals import location_created, location_edited
from .util import allowed_child_types, lookup_by_property


class ParentLocWidget(forms.Widget):
    def render(self, name, value, attrs=None):
        return get_template(
            'locations/manage/partials/parent_loc_widget.html'
        ).render(Context({
            'name': name,
            'value': value,
        }))


class LocTypeWidget(forms.Widget):
    def render(self, name, value, attrs=None):
        return get_template(
            'locations/manage/partials/loc_type_widget.html'
        ).render(Context({
            'name': name,
            'value': value,
        }))


class LocationForm(forms.Form):
    parent_id = forms.CharField(
        label=_('Parent'),
        required=False,
        widget=ParentLocWidget(),
    )
    name = forms.CharField(max_length=100)
    location_type = forms.CharField(widget=LocTypeWidget(), required=False)
    coordinates = forms.CharField(
        max_length=30,
        required=False,
        help_text=_("enter as 'lat lon' or 'lat, lon' "
                    "(e.g., '42.3652 -71.1029')"),
    )
    site_code = forms.CharField(
        label='Site Code',
        required=False,
        help_text=_("A unique system code for this location. "
                    "Leave this blank to have it auto generated"),
    )
    external_id = forms.CharField(
        label='External ID',
        required=False,
        help_text=_("A number referencing this location on an external system")
    )
    external_id.widget.attrs['readonly'] = True

    strict = True  # optimization hack: strict or loose validation
    # TODO remove user from parameters once all these branches are merged

    def __init__(self, location, bound_data=None, is_new=False, user=None,
                 *args, **kwargs):
        self.location = location
        self.is_new_location = is_new

        # seed form data from couch doc
        kwargs['initial'] = dict(self.location._doc)
        kwargs['initial']['parent_id'] = self.location.parent_id
        lat, lon = (getattr(self.location, k, None)
                    for k in ('latitude', 'longitude'))
        kwargs['initial']['coordinates'] = ('%s, %s' % (lat, lon)
                                            if lat is not None else '')

        self.custom_data = self.get_custom_data(bound_data, is_new)

        super(LocationForm, self).__init__(bound_data, *args, **kwargs)
        self.fields['parent_id'].widget.domain = self.location.domain
        self.fields['parent_id'].widget.user = user

        if not self.location.external_id:
            self.fields['external_id'].widget = forms.HiddenInput()

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = crispy.Layout(
            crispy.Fieldset(*self.get_fields(is_new))
        )

    def get_fields(self, is_new):
        if is_new:
            parent = (Location.get(self.location.parent_id)
                      if self.location.parent_id else None)
            child_types = allowed_child_types(self.location.domain, parent)
            return filter(None, [
                _("Location Information"),
                'name',
                'location_type' if len(child_types) > 1 else None,
            ])
        else:
            return [
                _("Location Information"),
                'name',
                'parent_id',
                'location_type',
                'coordinates',
                'site_code',
                'external_id',
            ]

    def get_custom_data(self, bound_data, is_new):
        from .views import LocationFieldsView

        existing = self.location.metadata

        # Don't show validation error preemptively on new user creation
        if is_new and bound_data is None:
            existing = None

        return CustomDataEditor(
            field_view=LocationFieldsView,
            domain=self.location.domain,
            # For new locations, only display required fields
            required_only=is_new,
            existing_custom_data=existing,
            post_dict=bound_data,
        )

    def is_valid(self):
        return all([
            super(LocationForm, self).is_valid(),
            self.custom_data.is_valid(),
        ])

    @property
    def errors(self):
        errors = super(LocationForm, self).errors
        errors.update(self.custom_data.errors)
        return errors

    def clean_parent_id(self):
        parent_id = self.cleaned_data['parent_id'] or self.location.parent_id
        parent = Location.get(parent_id) if parent_id else None
        self.cleaned_data['parent'] = parent

        if self.location._id is not None and self.location.parent_id != parent_id:
            # location is being re-parented

            if parent and self.location._id in parent.path:
                assert False, 'location being re-parented to self or descendant'

            if self.location.descendants:<commit_msg>Properly allow parent location reassignment<commit_after>import re

from django import forms
from django.template import Context
from django.template.loader import get_template
from django.utils.translation import ugettext as _

from crispy_forms.helper import FormHelper
from crispy_forms import layout as crispy
from dimagi.utils.couch.database import iter_docs
from dimagi.utils.decorators.memoized import memoized

from corehq.apps.custom_data_fields import CustomDataEditor
from corehq.apps.es import UserES
from corehq.apps.users.forms import MultipleSelectionForm
from corehq.apps.users.models import CommCareUser
from corehq.apps.users.util import raw_username, user_display_string

from .models import Location
from .signals import location_created, location_edited
from .util import allowed_child_types, lookup_by_property


class ParentLocWidget(forms.Widget):
    def render(self, name, value, attrs=None):
        return get_template(
            'locations/manage/partials/parent_loc_widget.html'
        ).render(Context({
            'name': name,
            'value': value,
        }))


class LocTypeWidget(forms.Widget):
    def render(self, name, value, attrs=None):
        return get_template(
            'locations/manage/partials/loc_type_widget.html'
        ).render(Context({
            'name': name,
            'value': value,
        }))


class LocationForm(forms.Form):
    parent_id = forms.CharField(
        label=_('Parent'),
        required=False,
        widget=ParentLocWidget(),
    )
    name = forms.CharField(max_length=100)
    location_type = forms.CharField(widget=LocTypeWidget(), required=False)
    coordinates = forms.CharField(
        max_length=30,
        required=False,
        help_text=_("enter as 'lat lon' or 'lat, lon' "
                    "(e.g., '42.3652 -71.1029')"),
    )
    site_code = forms.CharField(
        label='Site Code',
        required=False,
        help_text=_("A unique system code for this location. "
                    "Leave this blank to have it auto generated"),
    )
    external_id = forms.CharField(
        label='External ID',
        required=False,
        help_text=_("A number referencing this location on an external system")
    )
    external_id.widget.attrs['readonly'] = True

    strict = True  # optimization hack: strict or loose validation
    # TODO remove user from parameters once all these branches are merged

    def __init__(self, location, bound_data=None, is_new=False, user=None,
                 *args, **kwargs):
        self.location = location
        self.is_new_location = is_new

        # seed form data from couch doc
        kwargs['initial'] = dict(self.location._doc)
        kwargs['initial']['parent_id'] = self.location.parent_id
        lat, lon = (getattr(self.location, k, None)
                    for k in ('latitude', 'longitude'))
        kwargs['initial']['coordinates'] = ('%s, %s' % (lat, lon)
                                            if lat is not None else '')

        self.custom_data = self.get_custom_data(bound_data, is_new)

        super(LocationForm, self).__init__(bound_data, *args, **kwargs)
        self.fields['parent_id'].widget.domain = self.location.domain
        self.fields['parent_id'].widget.user = user

        if not self.location.external_id:
            self.fields['external_id'].widget = forms.HiddenInput()

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = crispy.Layout(
            crispy.Fieldset(*self.get_fields(is_new))
        )

    def get_fields(self, is_new):
        if is_new:
            parent = (Location.get(self.location.parent_id)
                      if self.location.parent_id else None)
            child_types = allowed_child_types(self.location.domain, parent)
            return filter(None, [
                _("Location Information"),
                'name',
                'location_type' if len(child_types) > 1 else None,
            ])
        else:
            return [
                _("Location Information"),
                'name',
                'parent_id',
                'location_type',
                'coordinates',
                'site_code',
                'external_id',
            ]

    def get_custom_data(self, bound_data, is_new):
        from .views import LocationFieldsView

        existing = self.location.metadata

        # Don't show validation error preemptively on new user creation
        if is_new and bound_data is None:
            existing = None

        return CustomDataEditor(
            field_view=LocationFieldsView,
            domain=self.location.domain,
            # For new locations, only display required fields
            required_only=is_new,
            existing_custom_data=existing,
            post_dict=bound_data,
        )

    def is_valid(self):
        return all([
            super(LocationForm, self).is_valid(),
            self.custom_data.is_valid(),
        ])

    @property
    def errors(self):
        errors = super(LocationForm, self).errors
        errors.update(self.custom_data.errors)
        return errors

    def clean_parent_id(self):
        if self.is_new_location:
            parent_id = self.location.parent_id
        else:
            parent_id = self.cleaned_data['parent_id'] or None
        parent = Location.get(parent_id) if parent_id else None
        self.cleaned_data['parent'] = parent

        if self.location._id is not None and self.location.parent_id != parent_id:
            # location is being re-parented

            if parent and self.location._id in parent.path:
                assert False, 'location being re-parented to self or descendant'

            if self.location.descendants:
{'fraction_non_alphanumeric': 0.09253104775231764, 'fraction_numerical': 0.003148504460381319, 'mean_word_length': 2.291594703511802, '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': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7366216', 'n_tokens_mistral': 3174, 'n_tokens_neox': 3069, 'n_words': 776}