from django import forms from django.urls import reverse, reverse_lazy from django.utils.safestring import mark_safe from django.utils.text import format_lazy from django.utils.translation import ugettext_lazy as _ from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit, Layout, HTML, Fieldset, Div from crispy_forms.bootstrap import Tab, TabHolder, PrependedText, FormActions from dal import autocomplete from leaflet.forms.widgets import LeafletWidget from apps.files.models import File, ImageFile from .models import CaseStudy, SpatialRefSys, PointOfInterest from .widgets import JSONFileListWidget SECTOR_HELP = { 'RN': _("Including electricity, heat or combined heat and power generation"), 'PG': '', 'ST': _('Biological, chemical, electrical, electromagnetic, electrochemical,' ' mechanical including gravitational potential, thermal, etc.'), 'SM': _("Including supply of minerals"), 'MA': '', } POWER_TECHNOLOGY_HELP = { 'PT': _('Lines, transformers, machinery, etc.'), 'HN': _('District heating/cooling, etc.'), 'OT': '', } def add_explanatory_text(model_choices, explanatory_text): return [ ( choice[0], mark_safe('%s
%s' % (choice[1], explanatory_text[choice[0]]) ) ) for choice in model_choices ] class MinimumZoomWidget(LeafletWidget): geometry_field_class = 'MinimumZoomField' class PointOfInterest(forms.models.ModelForm): def __init__(self, *args, **kwargs): super(PointOfInterest, self).__init__(*args, **kwargs) self.helper = FormHelper(self) self.helper.form_id = 'case-study-form' self.helper.form_class = 'form-horizontal' self.helper.form_method = 'post' self.helper.form_action = 'add' self.helper.label_class = 'col-lg-2' self.helper.field_class = 'col-lg-10' self.helper.include_media = False self.helper.form_action = reverse('point-of-interest-form') self.helper.add_input( Submit('submit', _('Submit'), css_class='btn-success center-block') ) class Meta: model = PointOfInterest widgets = { 'location': MinimumZoomWidget(attrs={ 'settings_overrides': { 'SCALE': False } }), } fields = [ 'title', 'location', 'synopsis', 'link', ] class BaseCaseStudyForm(forms.models.ModelForm): """Base form class for the CaseStudy model.""" def __init__(self, *args, **kwargs): super(BaseCaseStudyForm, self).__init__(*args, **kwargs) self.helper = FormHelper(self) self.helper.form_id = 'case-study-form' self.helper.form_class = 'form-horizontal' self.helper.form_method = 'post' self.helper.label_class = 'col-md-3' self.helper.field_class = 'col-md-9' self.helper.include_media = False # Parse number fields correctly for the locale number_fields = [ "area_of_land", "total_generation_capacity", "total_investment", "energy_storage_capacity", "energy_transmission_capacity", "area_of_land", "total_generation_capacity", "total_investment", ] for field_name in number_fields: if field_name in self.fields: self.fields[field_name].localize = True class Meta: model = CaseStudy fields = '__all__' widgets = { 'location': MinimumZoomWidget(attrs={ 'settings_overrides': { 'SCALE': False } }), } class ShortCaseStudyForm(BaseCaseStudyForm): """Short version of the CaseStudy form.""" def __init__(self, *args, **kwargs): super(ShortCaseStudyForm, self).__init__(*args, **kwargs) self.helper.add_input(Submit('submit', _('Submit'), css_class='btn-success center-block')) self.fields['sector_of_economy'].widget = forms.RadioSelect() self.fields['sector_of_economy'].required = False self.fields['sector_of_economy'].choices = add_explanatory_text( CaseStudy.SECTOR_CHOICES, SECTOR_HELP ) class Meta(BaseCaseStudyForm.Meta): fields = [ 'entry_name', 'location', 'sector_of_economy', 'positive_or_negative', 'country', 'area_of_land', 'land_ownership', 'land_ownership_details', 'location_context', 'type_of_ecosystem', 'describe_ecosystem', 'affected_communities', 'project_status', 'synopsis', 'full_description', 'video', 'media_coverage_mainstream', 'media_coverage_independent', 'community_voices' ] class BootstrapClearableFileInput(forms.ClearableFileInput): template_name = 'map/forms/widgets/file.html' def PreviousButton(): return HTML( format_lazy( "{prev}", prev=_("Previous") ) ) def NextButton(): return HTML( format_lazy( "{next}", next=_("Next") ) ) class LongCaseStudyForm(BaseCaseStudyForm): """Long version of the CaseStudy form.""" images = forms.FileField( label=_("Images"), widget=BootstrapClearableFileInput(attrs={ 'url': reverse_lazy('files:upload'), 'field': 'images_files', }), required=False ) images_files = forms.ModelMultipleChoiceField( queryset=ImageFile.objects.all(), widget=JSONFileListWidget(), required=False ) official_project_documents = forms.FileField( label=_("Official project documents"), widget=BootstrapClearableFileInput(attrs={ 'url': reverse_lazy('files:upload'), 'field': 'official_project_documents_files', }), required=False ) official_project_documents_files = forms.ModelMultipleChoiceField( queryset=File.objects.all(), widget=JSONFileListWidget(), required=False ) other_documents = forms.FileField( label=_("Other documents"), widget=BootstrapClearableFileInput(attrs={ 'url': reverse_lazy('files:upload'), 'field': 'other_documents_files', }), required=False ) other_documents_files = forms.ModelMultipleChoiceField( queryset=File.objects.all(), widget=JSONFileListWidget(), required=False ) shapefiles = forms.FileField( label=CaseStudy.shapefiles_label, help_text=CaseStudy.shapefiles_help_text, widget=BootstrapClearableFileInput(attrs={ 'url': reverse_lazy('files:upload'), 'field': 'shapefiles_files', }), required=False ) shapefiles_files = forms.ModelMultipleChoiceField( queryset=File.objects.all(), widget=JSONFileListWidget(), required=False ) coordinate_reference_system = forms.ModelChoiceField( label=_("Coordinate reference system"), queryset=SpatialRefSys.objects.all(), widget=autocomplete.ModelSelect2(url='srs-autocomplete'), initial=4326, ) def __init__(self, *args, **kwargs): super(LongCaseStudyForm, self).__init__(*args, **kwargs) self.fields['positive_case_type'].label = "" self.fields['negative_case_reasons'].label = "" self.fields['sector_of_economy'].widget = forms.RadioSelect() self.fields['sector_of_economy'].required = False self.fields['sector_of_economy'].choices = add_explanatory_text( CaseStudy.SECTOR_CHOICES, SECTOR_HELP ) self.fields['power_technology'].widget = forms.RadioSelect() self.fields['power_technology'].required = False self.fields['power_technology'].choices = add_explanatory_text( CaseStudy.POWER_TECHNOLOGY_CHOICES, POWER_TECHNOLOGY_HELP ) self.fields['project_owners'].required = True self.fields['shareholders'].required = True organising_vs_label = _( 'Socio-environmental impacts (negative and potentially positive)') organising_pro_label = _( 'Socio-environmental impacts (positive and potentially negative)') organising_other_label = _( 'Socio-environmental impacts (positive and negative)') self.fields['socioeconomic_benefits'].label = format_lazy( ( '{vs}' '{pro}' '{other}' ), vs=organising_vs_label, pro=organising_pro_label, other=organising_other_label ) organising_other_text = _( 'Please expand on your response given in the full description on page one.' ' For example, for positive impacts you need to go beyond emissions' ' savings, paying rent for land, or complying with environmental or social' ' legislation. For negative impacts you need to focus on substantive' ' impacts on vulnerable groups, violations of land rights or abusive labour' ' practices.') organising_vs_text = _( 'Please expand on your response given in the description. Note that we aim' ' to focus on violation of land rights / human rights / collective rights,' ' substantive negative impacts on vulnerable groups, aggression / threats /' ' violence, severe environmental and/or cultural impacts, abusive labor' ' practices, and corruption / governance issues, but feel free to cover any' ' additional aspect that you consider relevant. Please also describe and' ' analyze socio-environmental impacts that could be presented or considered' ' as positive.') organising_pro_text = _( 'Please expand on your response given in the description. Please also' ' describe and analyze socio-environmental impacts that could be considered' ' as negative.') self.fields['socioeconomic_benefits'].help_text = format_lazy( ( '{other}' '{vs}' '{pro}' ), vs=organising_vs_text, pro=organising_pro_text, other=organising_other_text ) self.helper.form_action = reverse('long-form') self.helper.layout = Layout( TabHolder( Tab(_("Basic information"), 'entry_name', 'location', 'country', 'shapefiles', 'shapefiles_files', 'coordinate_reference_system', 'name_of_territory_or_area', 'area_of_land', 'land_ownership', 'land_ownership_details', 'location_context', 'type_of_ecosystem', 'describe_ecosystem', 'affected_communities', 'people_affected_other', 'project_status', 'start_year', 'completion_year', 'synopsis', 'full_description', 'images', 'images_files', 'video', 'video_caption', 'video_credit', Fieldset( _("Owners and financiers"), 'project_owners', 'consultants_contractors', 'shareholders', 'financial_institutions', 'financial_institutions_other', ), Fieldset( _("Media reports and other communications"), 'media_coverage_mainstream', 'media_coverage_independent', 'community_voices', 'direct_comms', 'social_media_links' ), FormActions( NextButton() ) ), Tab( _("Technical and economic analysis"), 'sector_of_economy', Div( 'generation_type', 'generation_technology', css_class='power_generation_questions' ), Div( 'power_technology', css_class='energy_network_questions' ), Div( 'energy_details', css_class='energy_generation_network_and_storage_questions' ), Div( 'biomass_detail', 'total_generation_capacity', css_class='power_generation_questions' ), Div( 'energy_transmission_capacity', css_class='energy_network_questions' ), Div( 'energy_storage_capacity', css_class='energy_storage_questions' ), Div( PrependedText('total_investment', 'USD $'), 'contractor_or_supplier_of_technology', 'energy_customers', 'additional_technical_details', css_class='energy_generation_network_and_storage_questions' ), Div( 'minerals_or_commodities', 'minerals_or_commodities_other', 'use_in_energy_economy', 'use_in_energy_economy_other', 'project_life_span', 'size_of_concessions', 'projected_production_of_commodities', 'type_of_extraction', 'associated_infrastructure', css_class="mineral_commodity_questions" ), Div( 'manufacturing_type', 'manufacturing_description', 'manufacturing_related_tech', 'manufacturing_factors', 'manufacturing_factors_description', 'manufacturing_ownership', css_class="manufacturing_questions" ), FormActions( PreviousButton(), NextButton() ) ), Tab( _("Socio-environmental analysis"), HTML( format_lazy( "

{text}

", text=_( "In the following, we expect the analysis to reflect" " the perspective of the organization(s) or person(s)" " describing the case.") ) ), 'positive_or_negative', Div( HTML( format_lazy( "", text=_("What kind of case is this entry about?") ) ), Div( 'positive_case_type', 'negative_case_reasons', css_class='col-md-9', ), css_class='form-group', ), 'negative_case_reasons_other', 'socioeconomic_benefits', 'isolated_or_widespread', 'key_actors_involved', 'project_status_detail', 'obstacles_and_hindrances', 'negative_socioenvironmental_impacts', 'when_did_organising_start', 'who_has_been_involved', 'participation_mechanisms', 'identified_partnerships', Div( css_class="common_questions" ), FormActions( PreviousButton(), NextButton() ) ), Tab( _("Contact details"), 'contact_email', 'contact_phone', 'contact_website', PrependedText('contact_twitter', '@', placeholder='username'), 'contact_facebook', 'contact_other', 'shown_on_other_platforms', 'shown_on_other_platforms_detail', FormActions( PreviousButton(), NextButton() ) ), Tab( _("Uploads"), 'official_project_documents', 'official_project_documents_files', 'other_documents', 'other_documents_files', FormActions( PreviousButton(), Submit('submit', _('Submit'), css_class="btn-success pull-right") ) ))) class Meta(BaseCaseStudyForm.Meta): exclude = ('approved',) class Media: js = ( 'files/upload.js', )