import datetime from urllib import parse from django.contrib.auth.models import User from django.contrib.gis.db import models from django.db import connection from django.template.defaultfilters import slugify from django.utils.translation import ugettext as _ from django_extensions.db.fields import AutoSlugField from django_countries.fields import CountryField from multiselectfield import MultiSelectField from phonenumber_field.modelfields import PhoneNumberField from . import validators class CaseStudyDraft(models.Model): author = models.ForeignKey( User, on_delete=models.CASCADE ) data = models.TextField() class SpatialRefSys(connection.ops.spatial_ref_sys()): def __str__(self): return self.__unicode__() def __unicode__(self): return '{0.auth_name}:{0.auth_srid} {0.name}'.format(self) class Meta: proxy = True verbose_name = "spatial reference system" class CaseStudyQuerySet(models.QuerySet): def approved(self): return self.filter( approved=True ) class CaseStudy(models.Model): """Model for case studies submitted to the Ojuso Platform""" approved = models.BooleanField(default=False) # Choice lists for drop-downs SECTOR_CHOICES = ( ('RN', _('Renewable Energy Generation')), ('PG', _('Power Grids')), ('SM', _('Supply of Minerals')), ) POSITIVE_NEGATIVE_CHOICES = ( ('P', _('Positive')), ('N', _('Negative')) ) LAND_OWNERSHIP_CHOICES = ( ('PRI', _('Private Land')), ('PUB', _('Public Land')), ('COM', _('Community Land')), ('OTH', _('Other')), ) LOCATION_CONTEXT_CHOICES = ( ('RUR', _('Rural')), ('URB', _('Urban')), ('MIX', _('Mixed')), ) TYPE_OF_ECOSYSTEM_CHOICES = ( ('MARINE', _('Marine (e.g. Ocean, Sea)')), ('FRESH', _('Freshwater (e.g. Freshwater, Lake)')), ('FOREST', _('Forest/Jungle')), ('AGRI', _('Agricultural Land')), ('GRASS', _('Grassland')), ('DESERT', _('Desert (Tundra, Ice or Sand)')), ('WETLND', _('Wetland (Marsh, Mangrove, Peat Soil)')), ('URBAN', _('Urban')) ) PROJECT_STATUS_CHOICES = ( ('EXSTNG', _('Existing Project')), ('UCONST', _('Under Construction')), ('PROJCD', _('Projected Project')), ) FINANCIAL_INSTITUTIONS = ( ('AfDB', _('African Development Bank (AfDB)')), ('BADEA', _('Arab Bank for Economic Development in Africa (BADEA)')), ('ADB', _('Asian Development Bank (ADB)')), ('AIIB', _('Asian Infrastructure Investment Bank (AIIB)')), ('BSTDB', _('Black Sea Trade and Development Bank (BSTDB)')), ('CAF', _('Corporacion Andina de Fomento / Development Bank of Latin America (CAF)')), ('CDB', _('Caribbean Development Bank (CDB)')), ('CABEI', _('Central American Bank for Economic Integration (CABEI)')), ('EADB', _('East African Development Bank (EADB)')), ('ETDB', _('Economic Cooperation Organization Trade and Development Bank (ETDB)')), ('EDB', _('Eurasian Development Bank (EDB)')), ('EBRD', _('European Bank for Reconstruction and Development (EBRD)')), ('EC', _('European Commission (EC)')), ('EIB', _('European Investment Bank (EIB)')), ('IADB', _('Inter-American Development Bank Group (IDB, IADB)')), ('IFFIm', _('International Finance Facility for Immunisation (IFFIm)')), ('IFAD', _('International Fund for Agricultural Development (IFAD)')), ('IIB', _('International Investment Bank (IIB)')), ('IsDB', _('Islamic Development Bank (IsDB)')), ('FMO', _('Nederlandse Financieringsmaatschappij voor Ontwikkelingslanden NV (FMO)')), ('NDB', _('New Development Bank (NDB) (formerly BRICS Development Bank)')), ('NDF', _('The Nordic Development Fund')), ('NIB', _('Nordic Investment Bank (NIB)')), ('OFID', _('OPEC Fund for International Development (OFID)')), ('BOAD', _('West African Development Bank (BOAD)')), ('WB', _('World Bank')), ) GENERATION_TECHNOLOGY_CHOICES = ( (_('Wind energy'), ( ('SSWE', _('Small-scale (less than 500kW)')), ('LSWE', _('Large-scale (more than 500kW)')) )), (_('Photovoltaic electricity'), ( ('SSPV', _('Small-scale (less than 500kW)')), ('LSPV', _('Large-scale (more than 500kW)')) )), (_('Hydroelectric'), ( ('SHYD', _('Small-scale (less than 1MW)')), ('MHYD', _('Medium-scale (between 1-20MW)')), ('LHYD', _('Large-scale (more than 20MW - often not considered renewable)')), )), ('STHE', _('Solar thermal electricity (e.g using parabolic reflectors)')), ('GEOT', _('Geothermal electricity')), ('BIOG', _('Biogas turbine')), ('OTHB', _('Other biomass (including liquid/solid biofuel)')), ('OTHR', _('Other (tidal, wave etc)')) ) POWER_TECHNOLOGY_CHOICES = ( ('PT', _('Power transmission (grid lines, substations etc)')), ('ES', _('Energy storage (pumped storage, compressed air, battery systems etc')), ('OT', _('Others')) ) TYPE_OF_EXTRACTION_CHOICES = ( ('SUR', _('Surface (open pit/open cast/open cut mining)')), ('SUB', _('Sub-surface (underground mining)')), ('SEA', _('Seabed mining')), ('URB', _('Urban mining/recycling')) ) MINERAL_COMMODITY_CHOICES = ( ('ALU', _('Aluminium (Bauxite)')), ('ARS', _('Arsenic')), ('BER', _('Beryllium')), ('CAD', _('Cadmium')), ('CHR', _('Chromium')), ('COK', _('Coking')), ('COA', _('Coal (for steel)')), ('COP', _('Copper')), ('GAL', _('Gallium')), ('GER', _('Germanium')), ('GLD', _('Gold')), ('HRE', _('Heavy Rare Earth Elements (Gadolinium, Terbium, Dysprosium, Holmium, Erbium, Thulium, Ytterbium, Lutetium, Yttrium, Scandium)')), ('IRN', _('Iron')), ('LRE', _('Light Rare Earth Elements (Lanthanum, Cerium, Praseodymium, Neodymium, Promethium, Samarium, Europium)')), ('LED', _('Lead')), ('LIT', _('Lithium')), ('MAN', _('Manganese')), ('MER', _('Mercury')), ('MOL', _('Molybdenum')), ('NIC', _('Nickel')), ('NIO', _('Niobium')), ('PGM', _('Platinum group metals (ruthenium, rhodium, palladium, osmium, iridium, and platinum)')), ('RHE', _('Rhenium')), ('SIL', _('Silicon')), ('SIV', _('Silver')), ('TAN', _('Tantalum')), ('TEL', _('Tellurium')), ('THA', _('Thallium')), ('TIN', _('Tin')), ('TIT', _('Titanium')), ('TUN', _('Tungsten')), ('VAN', _('Vanadium')), ('ZNC', _('Zinc')), ('OTR', _('Other')) ) USE_IN_ENERGY_ECONOMY_CHOICES = ( ('WTM', _('Wind turbine manufacturing')), ('SPM', _('Solar panel manufacturing')), ('STM', _('Solar thermal system manufacturing')), ('HGM', _('Hydropower generator manufacturing')), ('GGM', _('Geothermal generator manufacturing')), ('ESS', _('Energy storage (inc. battery systems)')), ('OTR', _('Others')) ) POSITIVE_CASE_TYPE_CHOICES = ( ('CREP', _('Community renewable energy project')), ('EACP', _('Energy as a commons project')), ('PSEP', _('Public/state (federal, state, municipal) energy project')), ('CORS', _('A case of responsible sourcing/supply chain/lifecycle management')), ) NEGATIVE_CASE_REASONS_OTHER_TEXT = _('Other reasons') NEGATIVE_CASE_REASONS_CHOICES = ( ('VOLR', _('Violation of land rights')), ('VOHR', _('Violation of fundamental human rights, indigenous rights and/or other collective rights')), ('EIMP', _('Environmental impacts (severe impacts on ecosystems / violation of laws, plans or programs of \ environmental conservation or territorial governance systems etc.')), ('NCUL', _('Negative cultural impacts (erosion/destruction of bio-cultural heritage, impacts on sacred land \ etc)')), ('AGGR', _('Aggression/threats to community members opposed to the project, collaboration with organized crime \ etc')), ('ALAB', _('Abusive labour practices')), ('CRUP', _('Corruption and/or irregular permitting or contracting, conflicts of interest etc')), # # N.B. # If you add another field in here, you need to edit conditionalCheckboxes # in templates/map/form.html and increment the check for the 'other' field there. # If you don't, the 'other' detail entry won't show and hide at the appropriate # times. # ('OTHR', NEGATIVE_CASE_REASONS_OTHER_TEXT) ) # Dynamically generate a list of choices 40 years prior and after the current year. YEAR_CHOICES = [(r, r) for r in range((datetime.datetime.now().year - 40), (datetime.datetime.now().year + 41))] ## # Meta Fields ## # User who submitted case study author = models.ForeignKey( User, models.SET_NULL, blank=True, null=True, editable=False ) # Date and time of submission date_created = models.DateTimeField(auto_now_add=True, null=False) # Slug derived from entry_name, used in urls for SEO slug = AutoSlugField(populate_from=['entry_name'], editable=False) ## # First Screen - Basic information ## # 1.1 entry_name = models.CharField( verbose_name=_("Entry Name"), help_text=_("Enter the name of the entry. This should usually be the\ name of project."), max_length=128 ) # N/A - Not explicitly listed in spec location = models.PointField( verbose_name=_("Project location") ) # 1.2 sector_of_economy = models.CharField( verbose_name=_("Sector of economy"), help_text=_("Which sector of the renewable energy economy is most\ relevant?"), max_length=3, choices=SECTOR_CHOICES ) # 1.3 positive_or_negative = models.CharField( verbose_name=_("Positive or negative?"), help_text=_("Is the case study a positive case or a negative case?"), max_length=1, choices=POSITIVE_NEGATIVE_CHOICES ) # 1.4 country = CountryField( verbose_name=_("Country"), help_text=_("Select the country of the project") ) # 1.5.1 area_of_land = models.IntegerField( verbose_name=_("Approximate land area"), help_text=_("The area of land covered by the project (in km²)") ) # 1.5.2 land_ownership = models.CharField( verbose_name=_("Land ownership"), help_text=_("What type of ownership does the land fall under?"), max_length=3, choices=LAND_OWNERSHIP_CHOICES ) # 1.5.3 land_ownership_details = models.CharField( verbose_name=_("Land ownership details"), help_text=_("Please specify details about land ownership if you chose 'other'"), max_length=256, null=True, blank=True, ) # 1.5.4 location_context = models.CharField( verbose_name=_("Location"), help_text=_("Select the context that is most applicable to this case\ study."), max_length=3, choices=LOCATION_CONTEXT_CHOICES ) # 1.5.5 type_of_ecosystem = MultiSelectField( verbose_name=_("Type(s) of ecosystem"), help_text=_("Select the most relevant type(s)."), max_length=56, choices=TYPE_OF_ECOSYSTEM_CHOICES, default=None, null=True, blank=True ) # 1.5.5.3 describe_ecosystem = models.TextField( verbose_name=_("Describe the ecosystem"), help_text=_("In your own words, add more detail about the ecosystem."), ) # Was 1.5.6; spec not being followed here after request from client people_affected_indigenous = models.TextField( verbose_name=_("Indigenous people affected"), help_text=_("What group or groups of indigenous people are affected by this project? \ Please separate by newline."), blank=True ) people_affected_other = models.TextField( verbose_name=_("Non-indigenous people affected"), help_text=_("What other group or groups of people are affected by this project? \ Please separate by newline."), blank=True ) # 1.6 project_status = models.CharField( verbose_name=_("Status of Project"), help_text=_("What is the status of the current project?"), max_length=6, choices=PROJECT_STATUS_CHOICES ) # 1.7 start_year = models.IntegerField( verbose_name=_("Start year"), help_text=_("Select the year the project was started. \ If the project hasn't begun, select the projected start year."), choices=YEAR_CHOICES, default=None, null=True, blank=True ) # 1.8 completion_year = models.IntegerField( verbose_name=_("Completion year"), help_text=_("Select the year the project was completed. \ If the project hasn't finished, select the projected completion year."), choices=YEAR_CHOICES, default=None, null=True, blank=True ) # 1.9 synopsis = models.TextField( verbose_name=_("Synopsis"), help_text=_("Briefly describe the project. This will be displayed at\ the top of the case study page. Maximum 500 chars (about \ 3½ tweets)") ) # 1.10 full_description = models.TextField( verbose_name=_("Full Description"), help_text=_("Describe the project in full. Separate paragraphs with a\ new line Please add as much detail as you feel is necessary\ here.") ) # 1.11 project_owners = models.TextField( verbose_name=_("Project and facility owners"), help_text=_("List companies or organisations that own the project and/or facilities. Separate with a new line."), blank=True ) # 1.12 shareholders = models.TextField( verbose_name=_("Shareholders of the project owners"), help_text=_("List shareholders of the project owners you've just listed. Separate with a new line."), blank=True ) # 1.13.1 financial_institutions = MultiSelectField( verbose_name=_("Financial institutions"), help_text=_("Select any financial institutions that have or are considering extending \ loans or guarantees to the project."), choices=FINANCIAL_INSTITUTIONS, blank=True ) # 1.13.2 financial_institutions_other = models.TextField( verbose_name=_("Financial institutions – other"), help_text=_("List any other financial institutions not listed above. \ Put each on a new line."), blank=True ) # 1.14 energy_customers = models.TextField( verbose_name=_("Energy consumers"), help_text=_("List any wholesale energy customers that take energy from the development. E.g. 'national \ grids' or private energy suppliers. Please separate with a newline."), blank=True ) # 1.15.1 image = models.ImageField( verbose_name=_("Image") ) # 1.15.2 image_caption = models.CharField( verbose_name=_("Image caption"), max_length=240, default=None, null=True, ) # 1.15.3 image_credit = models.CharField( verbose_name=_("Image credit(s)"), max_length=240, default=None, null=True, ) # 1.16.1 video = models.URLField( verbose_name=_("Video URL"), help_text=_("Copy the URL to a YouTube or Vimeo video that relates to the case study."), max_length=80, validators=[validators.YouTubeOrVimeoValidator()], blank=True ) # 1.16.2 video_caption = models.CharField( verbose_name=_("Video caption"), max_length=240, blank=True, default=None, null=True, ) # 1.16.3 video_credit = models.CharField( verbose_name=_("Video credit(s)"), max_length=240, blank=True, default=None, null=True, ) # 1.17.1 media_coverage_mainstream = models.TextField( verbose_name=_("Links to media reports"), help_text=_("Provide any links to mainstream media coverage."), default=None, null=True, ) # 1.17.2 media_coverage_independent = models.TextField( verbose_name=_("Independent grassroots reports"), help_text=_("Provide any links to grassroots/independent media coverage."), default=None, null=True, ) # 1.18.1 community_voices = models.TextField( verbose_name=_("Community Voices"), help_text=_("Add any direct quotes from members of the community that \ relate to this project"), default=None, null=True, blank=True ) # 1.18.2 direct_comms = models.TextField( verbose_name=_("Reports of direct communications"), help_text=_("Add any reports of direct communication between community members and \ representatives of developers/companies/investors."), default=None, null=True, blank=True ) # 1.18.3 social_media_links = models.TextField( verbose_name=_("Social media links"), help_text=_("Add any links to social media accounts directly relating to the project."), max_length=500, default=None, null=True, blank=True ) ## # Second Screen - Technical and economic analysis ## # 2.1 - Renewable Energy Generation # 2.1.1 generation_technology = models.CharField( verbose_name=_("Generation technology"), help_text=_("Select the type of renewable energy generation that most applies to this case study."), max_length=4, choices=GENERATION_TECHNOLOGY_CHOICES, default=None, null=True, blank=True ) # 2.1.1.12 # Should be filled in if 2.1.1 was answered as biogas or biomass. biomass_detail = models.CharField( verbose_name=_("Description of feedstock"), help_text=_("If you selected biogas or biomass, please describe the feedstock (where the fuel came from e.g. \ corn, algae, anaerobic digestion, commercial waste etc)"), max_length=200, default=None, null=True, blank=True ) # 2.1.1.14 generation_technology_other = models.CharField( verbose_name=_("Other generation type"), help_text=_("If you selected other, please specify the generation technology (e.g. tidal, wave etc)"), max_length=200, default=None, null=True, blank=True ) # 2.1.2 total_generation_capacity = models.PositiveIntegerField( verbose_name=_("Total generation capacity (in kW)"), help_text=_("Please enter the total generation capacity of the project in kW"), default=None, null=True, blank=True, ) # 2.1.3 # TODO: Auto-completion based on previous entries so we can query case-studies with the same answer. generation_equipment_supplier = models.TextField( verbose_name=_("Generation equipment supplier"), help_text=_("Enter the supplier of the generation equipment. (E.g. Siemens)"), default=None, null=True, blank=True ) # 2.1.4 total_investment = models.IntegerField( verbose_name=_("Total investment (in USD)"), help_text=_("The approximate total investment for the project in USD."), default=None, null=True, blank=True ) # 2.1.5 technical_or_economic_details = models.TextField( verbose_name=_("Additional technical or economic details"), help_text=_("Specify any additional technical or economic details relating to the project."), blank=True ) # 2.2 - Power Grids / Energy Storage # 2.2.1 power_technology = models.CharField( verbose_name=_("Power technology"), help_text=_("Select the related energy technology."), max_length=2, choices=POWER_TECHNOLOGY_CHOICES, default=None, null=True, blank=True ) # 2.2.1.4 power_technology_other = models.CharField( verbose_name=_("Other power technology"), help_text=_("If you answered 'others', please specify the power technologies."), max_length=128, default=None, null=True, blank=True ) # 2.2.2 energy_storage_capacity = models.DecimalField( verbose_name=_("Energy storage capacity"), help_text=_("Enter the total capacity of the energy storage system in kilowatt-hours (kWh)."), max_digits=20, decimal_places=3, default=None, null=True, blank=True ) # 2.2.2.1 maximum_power_output = models.DecimalField( verbose_name=_('Maximum power output'), help_text=_('Enter the maximum power output of the storage system in kilowatts (kW).'), max_digits=12, decimal_places=3, default=None, null=True, blank=True ) # 2.2.2.2 discharge_time = models.DecimalField( verbose_name=_('Time for discharge from full capacity'), help_text=_('Enter the time it takes to discharge from full capacity at maximum power output (in hours).'), max_digits=6, decimal_places=3, default=None, null=True, blank=True ) # 2.2.3 contractor_or_supplier_of_technology = models.CharField( verbose_name=_('Contractor and/or supplier of technology'), help_text=_('List companies that act as contractors or suppliers of technology related to energy storage.'), max_length=256, default=None, null=True, blank=True ) # 2.2.4 approximate_total_investment = models.PositiveIntegerField( verbose_name=_('Approximate total investment'), help_text=_('Enter the approximate total investment in USD ($).'), default=None, null=True, blank=True ) # 2.2.5 additional_technical_details = models.CharField( verbose_name=_("Additional technical or economic details"), help_text=_("Add any additional details such as: length, from-to, voltage, substations etc"), max_length=512, default=None, null=True, blank=True ) # 2.3.1.1 minerals_or_commodities = models.CharField( verbose_name=_("Mineral commodity/commodities"), help_text=_("Select the mineral commodity that is primarily mined in this project"), max_length=3, choices=MINERAL_COMMODITY_CHOICES, default=None, null=True, blank=True ) # 2.3.1.2 minerals_or_commodities_other = models.CharField( verbose_name=_("Other mineral commodity"), help_text=_("Enter the mineral commodity that isn't in the list."), max_length=64, default=None, null=True, blank=True ) # 2.3.2 use_in_energy_economy = models.CharField( verbose_name=_("Potential use in renewable energy economy"), help_text=_("Select the potential use of the minerals in the renewable energy economy"), max_length=3, choices=USE_IN_ENERGY_ECONOMY_CHOICES, default=None, null=True, blank=True ) # 2.3.2.9 use_in_energy_economy_other = models.CharField( verbose_name=_('Other use in energy economy'), max_length=128, default=None, null=True, blank=True ) # 2.3.3.1 project_life_span = models.CharField( verbose_name=_("Project life span"), help_text=_("e.g. 12 years of production, 15 years overall"), max_length=200, blank=True ) # 2.3.3.2 size_of_concessions = models.CharField( verbose_name=_("Size of concessions"), help_text=_("Describe the size of concession(s) granted to company/companies (e.g. 'one concession encompassing\ 2,300 hectares')"), max_length=200, null=True, default=None, blank=True ) # 2.3.3.3 projected_production_of_commodities = models.CharField( verbose_name=_("Projected production of key commodities"), help_text=_("Describe the projected production of commodities per annum and overall (e.g. '40 million tonnes of\ iron ore per year, 200 million tonnes over 5 year life of mine'"), max_length=256, default=None, null=True, blank=True ) # 2.3.4 type_of_extraction = models.CharField( verbose_name=_("Type of extraction"), max_length=3, choices=TYPE_OF_EXTRACTION_CHOICES, default=None, null=True, blank=True ) # 2.3.5 associated_infrastructure = models.CharField( verbose_name=_("Associated infrastructure in the locality"), help_text=_("List any associated infrastructure in the locality (e.g. tailings dams/mine waste storage and \ treatment facilities; ore processing facilities; smelting facilities; hydroelectric dams/energy infrastructure;\ transport infrastructure e.g. roads or rail."), max_length=256, default=None, null=True, blank=True ) ## # Third Screen - Socio-economic analysis ## # 3.1.1 positive_case_type = models.CharField( verbose_name=_('What kind of positive case is this entry about?'), help_text=_('Select the most relevant type of positive case'), choices=POSITIVE_CASE_TYPE_CHOICES, max_length=4, default=None, null=True, blank=True, ) # 3.1.2 socioeconomic_benefits = models.TextField( verbose_name=_('Socio-economic benefits'), help_text=_('Please expand on your response given in the full description on page one. We would expect \ benefits to go beyond emissions savings, paying rent for land, or complying with environmental or social \ legislation'), default=None, null=True, blank=True ) # 3.1.3 + 3.2.5 key_actors_involved = models.TextField( verbose_name=_('Key actors involved (individual/organisational)'), blank=True, null=True ) # 3.1.4 project_status_detail = models.TextField( verbose_name=_('Current status of the project'), help_text=_("Describe the current status of the project, expanding beyond 'existing', 'under construction' etc"), default=None, null=True, blank=True ) # 3.1.5 obstacles_and_hindrances = models.CharField( verbose_name=_('Obstacles and hindrances'), help_text=_('List any obstacles or hindrances experienced in the course of the project'), max_length=512, default=None, null=True, blank=True ) # 3.1.6 identified_partnerships = models.CharField( verbose_name=_('Identified partnerships'), help_text=_('Are you looking for partnerships or have any clearly identified need? If so, please describe it \ here.'), max_length=256, default=None, null=True, blank=True ) # 3.1.7.1 + 3.2.8.1 contact_email = models.EmailField( verbose_name=_('Email address'), blank=True ) # 3.1.7.2 + 3.2.8.1 contact_phone = PhoneNumberField( verbose_name=_('Phone number'), help_text=_('Please include the international prefix, beginning with "+".'), blank=True ) # 3.1.7.3 + 3.2.8.1 contact_website = models.URLField( verbose_name=_('Website'), blank=True ) # 3.1.7.4 + 3.2.8.1 contact_twitter = models.CharField( verbose_name=_('Twitter username'), max_length=50, blank=True ) # 3.1.7.5 + 3.2.8.1 contact_facebook = models.URLField( verbose_name=_('Facebook page'), blank=True ) # 3.1.7.6 + 3.2.8.1 contact_other = models.TextField( verbose_name=_('Other contact details'), blank=True ) # 3.2.1 negative_case_reasons = MultiSelectField( verbose_name=("Reasons this is a negative case study"), choices=NEGATIVE_CASE_REASONS_CHOICES, default=None, null=True, blank=True ) # 3.2.1.9 negative_case_reasons_other = models.CharField( verbose_name=_("Other reason for negative case"), help_text=_("Please include other reasons, noting that we aim to focus on projects with substantive negative \ impacts on vulnerable groups."), max_length=512, default=None, null=True, blank=True ) # 3.2.2 negative_socioenvironmental_impacts = models.TextField( verbose_name=_("Describe the negative socio-environmental impacts"), help_text=_("Provide a detailed description of the negative socio-environmental impacts (please provide all \ relevant details, such as type of ecosystem and presence of any existing reserve in the area, \ , specific communities affected by the project, total geographic footprint of the project, and \ tenure system affected in the case of land grabs, kind of permits that were irregularly issued if \ this is the case."), default=None, null=True, blank=True ) # 3.2.3 isolated_or_widespread = models.TextField( verbose_name=_("Describe if the project is isolated or commonplace."), help_text=_("Is this an isolated project or are there similar projects in the same geographic area? If there \ are more, can you describe them? Are there any significant cumulative synergistic effects?"), default=None, null=True, blank=True ) # 3.2.4.1 when_did_organising_start = models.CharField( verbose_name=_("When did local organising efforts begin?"), help_text=_("Before the project started? During project implementation? After project implementation? \ Describe in your own words."), max_length=512, default=None, null=True, blank=True ) # 3.2.4.2 who_has_been_involved = models.TextField( verbose_name=_("Which communities, groups and organisations have been involved?"), blank=True, null=True ) # 3.2.4.3 participation_mechanisms = models.TextField( verbose_name=_("What mechanisms of participation have been used?"), help_text=_("e.g. direct action, local referendums, legal cases, letters or petitions etc"), blank=True ) # 3.2.6 potential_partnerships = models.CharField( verbose_name=_("Describe potential partnerships"), help_text=_("Are you looking for partnerships or do you have any clearly identified need? If so, please \ describe it here."), max_length=512, default=None, null=True, blank=True ) # 3.2.7 wants_conversation_with_ojuso = models.BooleanField( verbose_name=_("Would you like to have a conversation with the ojuso team?"), help_text=_("This would be a conversation about challenging or engaging related developers, companies and \ investors."), default=True ) ## # Fourth Screen - Uploads ## # 4.1 official_project_documents = models.ManyToManyField( 'files.File', related_name='official_project_document_for', verbose_name=_("Official project documents"), help_text=_("Attach any legal or official documents that relate to the project."), blank=True, ) # 4.2 other_documents = models.ManyToManyField( 'files.File', related_name='other_document_for', verbose_name=_("Other documents"), help_text=_("Attach any other documents that relate to the project."), blank=True, ) # 4.3.1 shapefiles = models.ManyToManyField( 'files.File', related_name='shapefile_for', verbose_name=_("Shapefiles"), help_text=_("If you have territory that you would like to show in relation to this project - e.g. Bienes \ Comunales de Ixtepec etc. This is a set of 3 or more (often 5-6) files with file extensions like \ .cpg, .dbf, .prj, .qpj, .shp, .shx"), blank=True ) # 4.3.2 coordinate_reference_system = models.ForeignKey( SpatialRefSys, null=True, blank=True, default=4326 ) # 4.3.3 name_of_territory_or_area = models.CharField( verbose_name=_("Name of territory or area"), max_length=512, default=None, null=True, blank=True ) # 4.4 shown_on_other_platforms = models.BooleanField( verbose_name=_("Is this case study shown on other platforms?"), default=True ) # 4.4.1 shown_on_other_platforms_detail = models.TextField( verbose_name=_("Shown on other platforms - Detail"), help_text=_("Please provide links to other places the case study appears."), blank=True ) objects = CaseStudyQuerySet.as_manager() def __str__(self): """The String representation of the case study. (Entry name with country name.)""" return "%s in %s" % (self.entry_name, self.country.name) def clean(self, *args, **kwargs): """Perform validation on the model as a whole and throw a ValidationError if anything isn't how it should be.""" pass def save(self, *args, **kwargs): """Override the save method to create a slug when the model is created. Slug is only created and never modified as we are basing our URLs on it and don't want it to change - ever.""" if not self.pk: # Newly created object, so set slug self.slug = slugify(self.entry_name) # Continue normal save method by calling original save method. super(CaseStudy, self).save(*args, **kwargs) def is_video_youtube(self): return self.video.count("youtube.com") > 0 def get_youtube_id(self): """Gets the 11 character YouTube video ID from the video field.""" return parse.parse_qs(parse.urlparse(self.video).query)["v"][0] def is_video_vimeo(self): return self.video.count("vimeo.com") > 0 def get_vimeo_id(self): """Gets the 11 number video ID from the video field.""" return parse.urlparse(self.video).path def get_negative_case_reasons_no_other(self): """Return a list of negative case reasons, minus the 'other' choice (if selected)""" choices = self.get_negative_case_reasons_list() if choices.count(self.NEGATIVE_CASE_REASONS_OTHER_TEXT) > 0: choices.remove(self.NEGATIVE_CASE_REASONS_OTHER_TEXT) return choices def get_renewable_generation_detail(self): """Prepend appropriate descriptive text when accessing renewable generation type.""" if self.generation_technology: if self.generation_technology.endswith('WE'): return _('Wind energy') + " – " + self.get_generation_technology_display() elif self.generation_technology.endswith('PV'): return _('Photovoltaic electricity') + " – " + self.get_generation_technology_display() elif self.generation_technology.endswith('HYD'): return _('Hydroelectric') + " – " + self.get_generation_technology_display() elif self.generation_technology == 'OTHR': return self.generation_technology_other else: return self.get_generation_technology_display() else: return "" class Meta: verbose_name_plural = 'case studies'