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 ) created = models.DateTimeField(auto_now_add=True) data = models.TextField() def __str__(self): return "{0.author.username}, {0.created:%Y-%m-%d %H:%M}".format(self) 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 project')), ('PG', _('Energy networks and energy storage facilities')), ('SM', _('Mining related to the renewable energy economy')), ('MA', _('Manufacturing and/or processing of equipment')) ) POSITIVE_NEGATIVE_CHOICES = ( ('P', _('There is/was an organising process in favour of the project')), ('N', _('There is/was an organising process against the project')), ('X', _('There is/was no organising process')), ('U', _('Unsure/unknown')) ) LAND_OWNERSHIP_CHOICES = ( ('PRI', _('Private land')), ('PUB', _('Public/state land')), ('COM', _('Community/communal/customary land')), ('CON', _('Contested/in conflict')), ('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')) ) AFFECTED_COMMUNITIES_CHOICES = ( ('INDIG', _('Indigenous')), ('AFRO', _('Afro-descendants')), ('MIG', _('Migrants')), ('REF', _('Refugees')), ('OTHER', _('Other communities or identities')), ) PROJECT_STATUS_CHOICES = ( ('INIT', _('Initiation/ideation')), ('PROJCD', _('In planning and design')), ('FAIL', _('Failed')), ('UCONST', _('Under construction')), ('EXSTNG', _('In operation')), ('DECOMM', _('Undergoing decommissioning')), ('END', _('Decommissioned')), ) 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_TYPE_CHOICES = ( ('POW', _('Power')), ('HOT', _('Heat/Cool')), ('CHP', _('Combined Heat/Cool and Power (CHP)')), ) GENERATION_TECHNOLOGY_CHOICES = ( ('BIO', _('Bio-energy')), ('GEOT', _('Geothermal electricity')), (_('Hydro'), ( ('uHYD', _('Micro hydro (<100kW)')), ('SHYD', _('Small-scale hydro (<1MW)')), ('MHYD', _('Medium-scale hydro (1-30MW)')), ('LHYD', _('Large-scale hydro (>30MW - often not considered renewable)')), )), (_('Marine'), ( ('WAVE', _('Wave')), ('TSTR', _('Tidal stream')), ('TBAR', _('Tidal barrage/lagoon')), ('TOTH', _('Other')), )), (_('Solar'), ( ('SSPV', _('Small-scale photovoltaic (<500kW)')), ('LSPV', _('Large-scale photovoltaic (>500kW)')), ( 'CSP', _('Concentrated solar power (CSP)')), ('PARA', _('Parabolic trough (open or enclosed)')), ('FRES', _('Fresnel reflector')), ('STIR', _('Dish Stirling')), )), (_('Wind'), ( ('SSWE', _('Small-scale wind (<500kW)')), ('LSWE', _('Large-scale wind (>500kW)')) )), ('OTHR', _('Other (tidal, wave etc)')) ) POWER_TECHNOLOGY_CHOICES = ( ('PT', _('Electrical power transmission')), ('ES', _('Energy storage')), ('HN', _('Heat networks')), ('OT', _('Other')), ) 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 = ( ('CPV', _('Concentrated solar power (CSP)')), ('EPT', _('Electrical power transmission infrastructure')), ('ESS', _('Energy storage')), ('GGM', _('Geothermal')), ('HGM', _('Hydropower')), ('HNT', _('Heat networks')), ('SPM', _('Solar PV')), ('STM', _('Solar thermal systems')), ('WTM', _('Wind power')), ('ESS', _("Don't know")), ('OTR', _('Other')) ) MANUFACTURING_TYPE_CHOICES = ( ('GENERATE', _('Manufacturing of renewable energy generation equipment')), ('TRANSSTORE', _('Manufacturing of energy transmission or storage equipment')), ('RECYCLE', _('Recycling / reusing equipment or raw materials')), ('DISPOSAL', _('Disposal of equipment')), ('OTHER', _('Other')), ) MANUFACTURING_RELATED_CHOICES = ( ('PV', _('Solar PV')), ('CSP', _('CSP')), ('WIND', _('Wind power')), ('HYDRO', _('Hydropower')), ('GEO', _('Geothermal')), ('TRANSMIT', _('Electrical power transmission infrastructure')), ('STORE', _('Energy storage')), ('HEAT', _('Heat networks')), ('OTHER', _('Other')), ('IDK', _('Unknown')), ) MANUFACTURING_FACTORS_CHOICES = ( ('LAND', _('Land use')), ('LABOR', _('Labor rights')), ('ENVIRO', _('Environmental factors')), ('LIFECYCLE', _('Lifecycle management')), ('OWN', _('Ownership')), ('OTHER', _('Other(s)')), ) POSITIVE_CASE_TYPE_CHOICES = ( ('CREP', _('Community project (co-)owned by individuals')), ('EACP', _('Community project owned by not-for-profit organizations and/or serving the public interest')), ('PSEP', _('Public/state (federal, state, municipal) project')), ('CORS', _('Reuse / Recycling / Circular economy project')), ('OTHR', _('Other(s)')) ) 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, on_delete=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) ## # Territory info ## location = models.PointField( verbose_name=_("Project location") ) shapefiles = models.ManyToManyField( 'files.File', related_name='shapefile_for', verbose_name=_("Geographic data"), 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. \ \ Hold down Control, or Command on a Mac, to select more than one. \ Let us know (database@ojuso.org) if you have other file types or need help and we \ can work out how to import it. You may have data as GeoPackage (gpkg), GeoJSON, \ KML, GML, etc. or have data in PostGIS or another spatial database management \ system already."), blank=True ) coordinate_reference_system = models.ForeignKey( SpatialRefSys, null=True, blank=True, default=4326, on_delete=models.PROTECT ) name_of_territory_or_area = models.CharField( verbose_name=_("Name of territory or area"), max_length=512, blank=True ) ## # First Screen - Basic information ## # 1.1 entry_name = models.CharField( verbose_name=_("Entry Name"), help_text=_("This should usually be the name of the project. \ If you are writing this case study in a language not used \ in the locale of its project, you should provide its local name \ first, as well as any translated name."), max_length=128 ) # 1.2 sector_of_economy = models.CharField( verbose_name=_("Sector of economy"), max_length=3, choices=SECTOR_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 / tenure"), 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.TextField( verbose_name=_("Land ownership details"), help_text=_("

Please specify details about land ownership, including \ conflicting claims, unrecognized customary rights, conflicts \ around land lease or purchase contracts, etc.\ \

We understand this is a difficult question, so \ please try to provide just the information you know. \ If we have any major questions we will ask them in the moderation process.

"), max_length=256, 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"), max_length=56, choices=TYPE_OF_ECOSYSTEM_CHOICES, blank=True ) # 1.5.5.3 describe_ecosystem = models.TextField( verbose_name=_("Describe the ecosystem"), ) affected_communities = MultiSelectField( verbose_name=_("Communities or identities present in the project area"), max_length=50, choices=AFFECTED_COMMUNITIES_CHOICES, blank=True ) # XXX Delete after migration 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 ) # XXX Delete after migration 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"), max_length=6, choices=PROJECT_STATUS_CHOICES ) # 1.7 start_year = models.IntegerField( verbose_name=_("Construction start year"), help_text=_("Select the year project construction began. If the project is not yet \ in construction, select the assumed start year as detailed in company \ information or media."), choices=YEAR_CHOICES, blank=True, null=True ) # 1.8 completion_year = models.IntegerField( verbose_name=_("Operation start year"), help_text=_("Select the year the project's operation and maintenance (O&M) phase began. \ If the project is not yet in operation, select the year operation is expected \ to begin as detailed in company information or media."), 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 two\ new lines. 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. \ Provide company numbers etc. if available. Separate with a new line."), blank=True ) consultants_contractors = models.TextField( verbose_name=_("Consultants and contractors"), help_text=_("List consultants, planners or organisations that are doing the planning, \ construction, operation or maintenance work relating to the project \ and/or facilities. Separate each with a new line."), ) # 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 (public or private) 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 service consumers/off-takers"), help_text=_("List any energy customers/off-takers that take energy from the \ development. E.g. 'national grids' or private energy suppliers. \ Also refer to if carbon markets, credits, blockchain etc. are \ involved in the process. Please separate with a new line."), blank=True ) # 1.15.1, 1.15.2, 1.15.3 images = models.ManyToManyField( 'files.ImageFile', related_name='image_for', verbose_name=_("Images"), blank=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, ) # 1.16.3 video_credit = models.CharField( verbose_name=_("Video credit(s)"), max_length=240, blank=True, ) # 1.17.1 media_coverage_mainstream = models.TextField( verbose_name=_("Links to media reports"), help_text=_("Provide any links to mainstream media coverage."), blank=True, ) # 1.17.2 media_coverage_independent = models.TextField( verbose_name=_("Independent grassroots reports"), help_text=_("Provide any links to grassroots/independent media coverage."), blank=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"), 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. If you have files \ to upload, you can do this in 'other documents' on the 'uploads' tab."), 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, blank=True, ) ## # Second Screen - Technical and economic analysis ## ## Energy generation project generation_type = models.CharField( verbose_name=_('What is being generated?'), max_length=4, choices=GENERATION_TYPE_CHOICES, blank=True ) 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, blank=True ) generation_technology_other = models.CharField( verbose_name=_("Further details"), help_text=_("If you selected other, or if you would like to further define what you have chosen, \ please specify the generation technology further. For example, if you chose solar PV \ it is most likely to be a crystalline silicon type, but maybe it is not."), max_length=200, blank=True ) # Should be filled in if generation_technology was answered as bio-energy biomass_detail = models.CharField( verbose_name=_("Bio-energy feedstock"), help_text=_("
\

Please describe the source of the fuel and how it is processed/used. \ Please consider:\

\ \

We do not expect users to know this information, but if you do \ it may be useful to give a fuller picture.\

"), max_length=200, 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"), blank=True, null=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(s)"), help_text=_("Enter the supplier of the generation equipment. (E.g. Siemens Gamesa, GE, Alstom, Vestas, Hanwha Q CELLS, Mitsubishi, First Solar, Jinko Solar, Trina Solar, Suzlon Energy, Statkraft, Shanghai Electric, Ballard Power Systems, Panasonic, etc.)"), 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."), blank=True, null=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"), max_length=2, choices=POWER_TECHNOLOGY_CHOICES, blank=True ) # 2.2.1.4 power_technology_other = models.CharField( verbose_name=_("Further information about power technology"), max_length=128, blank=True ) energy_storage_capacity = models.DecimalField( verbose_name=_("Total storage capacity (kWh)"), max_digits=20, decimal_places=3, blank=True, null=True, ) energy_transmission_capacity = models.DecimalField( verbose_name=_("Total transmission capacity (kW)"), max_digits=20, decimal_places=3, blank=True, null=True, ) # XXX Delete after migration 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, blank=True, null=True, ) # XXX Delete after migration 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, blank=True, null=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 – e.g. Siemens Gamesa, GE, Alstom, Vestas, Hanwha Q CELLS, Mitsubishi, First Solar, Jinko Solar, Trina Solar, Suzlon Energy, Statkraft, Shanghai Electric, Ballard Power Systems, Panasonic, etc'), max_length=256, blank=True, ) # 2.2.4 approximate_total_investment = models.PositiveIntegerField( verbose_name=_('Approximate total investment'), help_text=_('Enter the approximate total investment in USD ($).'), blank=True, default=None, null=True, ) # 2.2.5 additional_technical_details = models.TextField( verbose_name=_("Additional technical or economic details"), help_text=_("Add any additional details such as: length, from-to, voltage, \ substations, power output, (dis)charge rates, how this technology or \ project interacts with the energy system (e.g. provides reactive power \ to ensure power supply in phase etc.)"), blank=True ) ## # Mining ## minerals_or_commodities = models.CharField( verbose_name=_("Primary mineral mined"), help_text=_("What mineral commodity is primarily mined in this project?"), max_length=3, choices=MINERAL_COMMODITY_CHOICES, blank=True ) minerals_or_commodities_other = models.TextField( verbose_name=_("Other mineral commodities"), help_text=_("Enter any mineral commodities not in the list. Separate each with a new line."), blank=True ) use_in_energy_economy = MultiSelectField( verbose_name=_("Potential use in renewable energy economy"), max_length=128, choices=USE_IN_ENERGY_ECONOMY_CHOICES, blank=True ) use_in_energy_economy_other = models.CharField( verbose_name=_('Other'), max_length=128, blank=True ) 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 ) size_of_concessions = models.CharField( verbose_name=_("Size of concessions (land/marine area)"), help_text=_("Describe the size of concession(s) granted to company/companies (e.g. 'one concession of 2,300 hectares')"), max_length=200, blank=True ) projected_production_of_commodities = models.CharField( verbose_name=_("Estimated production of key commodities"), help_text=_('Describe the projected production of commodities per annum and overall.
\ For example, "40 million tonnes of iron ore per year", "200 million tonnes over 5 year life of mine"'), max_length=256, blank=True ) type_of_extraction = models.CharField( verbose_name=_("Type of extraction"), max_length=3, choices=TYPE_OF_EXTRACTION_CHOICES, blank=True ) 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, blank=True ) ## Manufacturing manufacturing_type = models.CharField( verbose_name=_("Which of the following options best describes this case?"), max_length=16, choices=MANUFACTURING_TYPE_CHOICES, blank=True ) manufacturing_description = models.TextField( verbose_name=_("Description"), help_text=_("Briefly describe manufacturing process and components/outputs.\ (less than 500 characters, about 2 tweets)."), max_length=500, blank=True ) manufacturing_related_tech = MultiSelectField( verbose_name=_("What technology is this case related to?"), max_length=128, choices=MANUFACTURING_RELATED_CHOICES, blank=True ) manufacturing_factors = MultiSelectField( verbose_name=_("Choose the factors that make this case remarkable, in a positive or negative way"), max_length=128, choices=MANUFACTURING_FACTORS_CHOICES, blank=True ) manufacturing_factors_description = models.TextField( verbose_name=_("Describe these factors"), blank=True ) manufacturing_ownership = models.TextField( verbose_name=_("Describe the ownership structure of the project and its relation with the local community"), blank=True ) ## # Socio-economic analysis ## positive_or_negative = models.CharField( verbose_name=_("What is the relationship of local community organization(s) to this project?"), max_length=1, choices=POSITIVE_NEGATIVE_CHOICES ) positive_case_type = models.CharField( verbose_name=_('What kind of case is this entry about?'), help_text=_('Select the most relevant type of positive case'), choices=POSITIVE_CASE_TYPE_CHOICES, max_length=4, blank=True, ) negative_case_reasons = MultiSelectField( verbose_name=("What kind of case is this entry about?"), choices=NEGATIVE_CASE_REASONS_CHOICES, blank=True ) socioeconomic_benefits = models.TextField( verbose_name=_('Socio-economic impacts'), blank=True ) negative_socioenvironmental_impacts = models.TextField( verbose_name=_("Describe the socio-environmental impacts (positive and negative):"), help_text=_("Provide a detailed description of the socio-environmental impacts \ (please provide all relevant details, such as type of ecosystem and \ presence of any existing reserve in the area, land to have increased \ biodiversity as a result of the project, new protection of lands/waters, \ 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."), blank=True ) isolated_or_widespread = models.TextField( verbose_name=_("Is the project part of developments which are causing a cumulative effect?"), help_text=_("Is this an isolated project or are there similar projects in the same \ geographic area? If so, can you describe them? Is there an analysis of \ cumulative or synergetic effects?"), blank=True ) key_actors_involved = models.TextField( verbose_name=_('Key actors involved (individual/organisational)'), blank=True ) project_status_detail = models.TextField( verbose_name=_('Current status of the case'), help_text=_("Describe the current situation and likely future scenarios."), blank=True ) obstacles_and_hindrances = models.TextField( verbose_name=_('Current status of the organizing process around this case'), help_text=_('Please describe the status of the organizing process, including the obstacles and hindrances faced.'), max_length=512, blank=True ) identified_partnerships = models.CharField( verbose_name=_('Identified partnerships'), help_text=_('Are you, or the organizing process that you represent, looking for partnerships, \ or have any clearly identified need? If so, please describe and we will try \ to connect you to appropriate partners.'), max_length=256, 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, 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, blank=True ) # 3.2.4.2 who_has_been_involved = models.TextField( verbose_name=_("Which communities, groups and organisations have been involved?"), blank=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.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 ) ## # Contact details ## contact_email = models.EmailField( verbose_name=_('Email address'), blank=True ) contact_phone = PhoneNumberField( verbose_name=_('Phone number'), help_text=_('Please include the international prefix, beginning with "+".'), blank=True ) contact_website = models.URLField( verbose_name=_('Website'), blank=True ) contact_twitter = models.CharField( verbose_name=_('Twitter username'), max_length=50, blank=True ) contact_facebook = models.URLField( verbose_name=_('Facebook page'), blank=True ) contact_other = models.TextField( verbose_name=_('Other contact details'), blank=True ) ## # 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. \ Hold down Control, or Command on a Mac, to select more than one."), 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. \ Hold down Control, or Command on a Mac, to select more than one."), 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' class PointOfInterestQuerySet(models.QuerySet): def approved(self): return self.filter( approved=True ) class PointOfInterest(models.Model): class Meta: verbose_name_plural = 'points of interest' def __str__(self): return self.title objects = PointOfInterestQuerySet.as_manager() author = models.ForeignKey( User, models.SET_NULL, blank=True, null=True, editable=False ) date_created = models.DateTimeField(auto_now_add=True, null=False) slug = AutoSlugField(populate_from=['title'], editable=False) approved = models.BooleanField(default=False) title = models.CharField(max_length=128) location = models.PointField() synopsis = models.TextField() link = models.URLField()