Add updated front end, updated CaseStudy model and profiles app
This commit is contained in:
parent
f91b4d2a2a
commit
43d6ec989b
@ -1,13 +1,14 @@
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Submit
|
||||
from crispy_forms.layout import Submit, Layout
|
||||
from crispy_forms.bootstrap import Tab, TabHolder
|
||||
from leaflet.forms.widgets import LeafletWidget
|
||||
from moderation.forms import BaseModeratedObjectForm
|
||||
|
||||
from .models import CaseStudy
|
||||
|
||||
|
||||
class BaseCaseStudyForm(forms.ModelForm):
|
||||
class BaseCaseStudyForm(BaseModeratedObjectForm):
|
||||
"""Base form class for the CaseStudy model."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BaseCaseStudyForm, self).__init__(*args, **kwargs)
|
||||
@ -52,6 +53,11 @@ class ShortCaseStudyForm(BaseCaseStudyForm):
|
||||
'synopsis',
|
||||
'full_description',
|
||||
'image',
|
||||
'image_caption',
|
||||
'image_credit',
|
||||
'video',
|
||||
'media_coverage_mainstream',
|
||||
'media_coverage_independent',
|
||||
'community_voices'
|
||||
]
|
||||
|
||||
@ -61,6 +67,47 @@ class LongCaseStudyForm(BaseCaseStudyForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LongCaseStudyForm, self).__init__(*args, **kwargs)
|
||||
self.helper.form_action = reverse('long-form')
|
||||
self.helper.layout = Layout(
|
||||
TabHolder(
|
||||
Tab("First Page",
|
||||
'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',
|
||||
'affects_indigenous',
|
||||
'affects_indigenous_detail',
|
||||
'project_status',
|
||||
'synopsis',
|
||||
'full_description',
|
||||
'image',
|
||||
'image_caption',
|
||||
'image_credit',
|
||||
'video',
|
||||
'media_coverage_mainstream',
|
||||
'media_coverage_independent',
|
||||
'community_voices'),
|
||||
Tab(
|
||||
"Second Page",
|
||||
'generation_technology',
|
||||
'biomass_detail',
|
||||
'generation_technology_other',
|
||||
'total_generation_capacity',
|
||||
'total_investment',
|
||||
'technical_or_economic_details',
|
||||
'power_technology',
|
||||
'power_technology_other',
|
||||
'energy_storage_capacity',
|
||||
)))
|
||||
|
||||
|
||||
|
||||
|
||||
class Meta(BaseCaseStudyForm.Meta):
|
||||
fields = '__all__'
|
||||
fields = '__all__'
|
111
apps/map/migrations/0010_auto_20171011_1606.py
Normal file
111
apps/map/migrations/0010_auto_20171011_1606.py
Normal file
@ -0,0 +1,111 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-11 16:06
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import apps.map.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('map', '0009_auto_20171007_1544'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='completion_year',
|
||||
field=models.IntegerField(blank=True, choices=[(1977, 1977), (1978, 1978), (1979, 1979), (1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024), (2025, 2025), (2026, 2026), (2027, 2027), (2028, 2028), (2029, 2029), (2030, 2030), (2031, 2031), (2032, 2032), (2033, 2033), (2034, 2034), (2035, 2035), (2036, 2036), (2037, 2037), (2038, 2038), (2039, 2039), (2040, 2040), (2041, 2041), (2042, 2042), (2043, 2043), (2044, 2044), (2045, 2045), (2046, 2046), (2047, 2047), (2048, 2048), (2049, 2049), (2050, 2050), (2051, 2051), (2052, 2052), (2053, 2053), (2054, 2054), (2055, 2055), (2056, 2056), (2057, 2057)], default=None, help_text="Select the year the project was completed. If the project hasn't finished, select the projected completion year.", null=True, verbose_name='Completion year'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='direct_comms',
|
||||
field=models.TextField(default=None, help_text='Add any reports of direct communication between community members and representatives of developers/companies/investors.', max_length=500, null=True, verbose_name='Reports of direct communications'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='energy_customers',
|
||||
field=models.CharField(blank=True, default=None, help_text="List any wholesale energy customers that take energy from the development. E.g. 'national grids' or private energy suppliers.", max_length=120, null=True, verbose_name='Energy consumers'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='financial_institutions',
|
||||
field=models.CharField(blank=True, default=None, help_text='List banks and other financial institutions that have or are considering extending loans or guarantees to the project. Separate with a comma.', max_length=120, null=True, verbose_name='Financial institutions'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='image_caption',
|
||||
field=models.CharField(default=None, max_length=500, null=True, verbose_name='Image caption'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='image_credit',
|
||||
field=models.CharField(default=None, max_length=200, null=True, verbose_name='Image credit(s)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='media_coverage_independent',
|
||||
field=models.TextField(default=None, help_text='Provide any links to grassroots/independent media coverage.', max_length=500, null=True, verbose_name='Independent grassroots reports'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='media_coverage_mainstream',
|
||||
field=models.TextField(default=None, help_text='Provide any links to mainstream media coverage.', max_length=500, null=True, verbose_name='Links to media reports'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='project_owners',
|
||||
field=models.CharField(blank=True, default=None, help_text='List companies or organisations that own the project and/or facilities. Separate with a comma.', max_length=120, null=True, verbose_name='Project and facility owners'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='shareholders',
|
||||
field=models.CharField(blank=True, default=None, help_text="List shareholders of the project owners you've just listed. Separate with a comma.", max_length=120, null=True, verbose_name='Shareholders of the project owners'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='social_media_links',
|
||||
field=models.TextField(blank=True, default=None, help_text='Add any links to social media accounts directly relating to the project.', max_length=500, null=True, verbose_name='Social media links'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='start_year',
|
||||
field=models.IntegerField(blank=True, choices=[(1977, 1977), (1978, 1978), (1979, 1979), (1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024), (2025, 2025), (2026, 2026), (2027, 2027), (2028, 2028), (2029, 2029), (2030, 2030), (2031, 2031), (2032, 2032), (2033, 2033), (2034, 2034), (2035, 2035), (2036, 2036), (2037, 2037), (2038, 2038), (2039, 2039), (2040, 2040), (2041, 2041), (2042, 2042), (2043, 2043), (2044, 2044), (2045, 2045), (2046, 2046), (2047, 2047), (2048, 2048), (2049, 2049), (2050, 2050), (2051, 2051), (2052, 2052), (2053, 2053), (2054, 2054), (2055, 2055), (2056, 2056), (2057, 2057)], default=None, help_text="Select the year the project was started. If the project hasn't begun, select the projected start year.", null=True, verbose_name='Start year'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='video_caption',
|
||||
field=models.CharField(default=None, max_length=500, null=True, verbose_name='Video caption'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='video_credit',
|
||||
field=models.CharField(default=None, max_length=500, null=True, verbose_name='Video credit(s)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='affects_indigenous',
|
||||
field=models.BooleanField(help_text='Does the project affect indigenous communities?', verbose_name='Affects indigenous people?'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='community_voices',
|
||||
field=models.TextField(help_text='Add any direct quotes from members of the community that relate to this project', verbose_name='Community Voices'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='date_created',
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='land_ownership_details',
|
||||
field=models.CharField(blank=True, help_text="Please specify details about land ownership if you chose 'other'", max_length=256, null=True, verbose_name='Land ownership details'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='video',
|
||||
field=models.URLField(help_text='Copy the URL to a related YouTube™ video that relates to the case study.', max_length=43, validators=[apps.map.validators.YoutubeURLValidator()], verbose_name='YouTube Video'),
|
||||
),
|
||||
]
|
20
apps/map/migrations/0011_casestudy_generation_technology.py
Normal file
20
apps/map/migrations/0011_casestudy_generation_technology.py
Normal file
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-12 15:52
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('map', '0010_auto_20171011_1606'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='generation_technology',
|
||||
field=models.CharField(blank=True, choices=[('SSWE', 'Small-scale wind energy (less than 500kW)'), ('LSWE', 'Large-scale wind energy (more than 500kW)'), ('SSPV', 'Small-scale photovoltaic electricity (less than 500kW)'), ('LSPV', 'Large-scale photovoltaic electricity (more than 500kW)'), ('STHE', 'Solar thermal electricity (e.g using parabolic reflectors)'), ('SHYD', 'Small hydroelectric (less than 1MW)'), ('MHYD', 'Medium hydroelectric (between 1-20MW)'), ('LHYD', 'Large hydroelectric (more than 20MW - often not considered renewable)'), ('GEOT', 'Geothermal electricity'), ('BIOG', 'Biogas turbine'), ('OTHB', 'Other biomass (including liquid/solid biofuel)')], default=None, help_text='Select the type of renewable energy generation that most applies to this case study.', max_length=4, null=True, verbose_name='Generation technology'),
|
||||
),
|
||||
]
|
47
apps/map/migrations/0012_auto_20171012_1610.py
Normal file
47
apps/map/migrations/0012_auto_20171012_1610.py
Normal file
@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-12 16:10
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.contrib.gis.db.models.fields
|
||||
from django.db import migrations, models
|
||||
import django_countries.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('map', '0011_casestudy_generation_technology'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='biomass_detail',
|
||||
field=models.CharField(blank=True, default=None, 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, null=True, verbose_name='Generation technology detail'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='generation_technology_other',
|
||||
field=models.CharField(blank=True, default=None, help_text='If you selected other, please specify the generation technology (e.g. tidal, wave etc)', max_length=200, null=True, verbose_name='Other generation type'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='total_generation_capacity',
|
||||
field=models.IntegerField(blank=True, default=None, help_text='Please enter the total generation capacity of the project in kW', null=True, verbose_name='Total generation capacity (in kW)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='country',
|
||||
field=django_countries.fields.CountryField(help_text='Select the country of the project', max_length=2, verbose_name='Country field'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='generation_technology',
|
||||
field=models.CharField(blank=True, choices=[('SSWE', 'Small-scale wind energy (less than 500kW)'), ('LSWE', 'Large-scale wind energy (more than 500kW)'), ('SSPV', 'Small-scale photovoltaic electricity (less than 500kW)'), ('LSPV', 'Large-scale photovoltaic electricity (more than 500kW)'), ('STHE', 'Solar thermal electricity (e.g using parabolic reflectors)'), ('SHYD', 'Small hydroelectric (less than 1MW)'), ('MHYD', 'Medium hydroelectric (between 1-20MW)'), ('LHYD', 'Large hydroelectric (more than 20MW - often not considered renewable)'), ('GEOT', 'Geothermal electricity'), ('BIOG', 'Biogas turbine'), ('OTHB', 'Other biomass (including liquid/solid biofuel)'), ('OTHR', 'Other (tidal, wave etc)')], default=None, help_text='Select the type of renewable energy generation that most applies to this case study.', max_length=4, null=True, verbose_name='Generation technology'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='location',
|
||||
field=django.contrib.gis.db.models.fields.PointField(help_text='Place a marker using the tools on the left of the map. Zoom in as far as you can so the placement is accurate (important)', srid=4326, verbose_name='Project location'),
|
||||
),
|
||||
]
|
35
apps/map/migrations/0013_auto_20171012_1640.py
Normal file
35
apps/map/migrations/0013_auto_20171012_1640.py
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-12 16:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('map', '0012_auto_20171012_1610'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='technical_or_economic_details',
|
||||
field=models.CharField(blank=True, default=None, help_text='Specify any additional technical or economic details relating to the project.', max_length=500, null=True, verbose_name='Additional technical or economic details'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='total_investment',
|
||||
field=models.IntegerField(blank=True, default=None, help_text='The approximate total investment for the project in USD.', null=True, verbose_name='Total investment (in USD)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='generation_technology',
|
||||
field=models.CharField(blank=True, 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)')], default=None, help_text='Select the type of renewable energy generation that most applies to this case study.', max_length=4, null=True, verbose_name='Generation technology'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='total_generation_capacity',
|
||||
field=models.PositiveIntegerField(blank=True, default=None, help_text='Please enter the total generation capacity of the project in kW', null=True, verbose_name='Total generation capacity (in kW)'),
|
||||
),
|
||||
]
|
25
apps/map/migrations/0014_auto_20171025_2035.py
Normal file
25
apps/map/migrations/0014_auto_20171025_2035.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-25 20:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('map', '0013_auto_20171012_1640'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='power_technology',
|
||||
field=models.CharField(blank=True, choices=[('PT', 'Power transmission (grid lines, substations etc)'), ('ES', 'Energy storage (pumped storage, compressed air, battery systems etc'), ('OT', 'Others')], default=None, help_text='Select the related energy technology.', max_length=2, null=True, verbose_name='Power technology'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='power_technology_other',
|
||||
field=models.CharField(blank=True, default=None, help_text="If you answered 'others', please specify the power technologies.", max_length=128, null=True, verbose_name='Other power technology'),
|
||||
),
|
||||
]
|
25
apps/map/migrations/0015_auto_20171030_1550.py
Normal file
25
apps/map/migrations/0015_auto_20171030_1550.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-30 15:50
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('map', '0014_auto_20171025_2035'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='energy_storage_capacity',
|
||||
field=models.IntegerField(blank=True, default=None, help_text='Enter the total capacity of the energy storage system.', null=True, verbose_name='Energy storage capacity'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='casestudy',
|
||||
name='affects_indigenous_detail',
|
||||
field=models.CharField(blank=True, default=None, help_text='What group of indigenous people does the community belong to?', max_length=256, null=True, verbose_name='Affects Indigenous - Details'),
|
||||
),
|
||||
]
|
40
apps/map/migrations/0016_auto_20171031_1442.py
Normal file
40
apps/map/migrations/0016_auto_20171031_1442.py
Normal file
@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-31 14:42
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('map', '0015_auto_20171030_1550'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='definition_of_affected_territories',
|
||||
field=models.CharField(blank=True, default=None, help_text='In your own words, define the territories that the project will affect.', max_length=512, null=True, verbose_name='Definition of affected territories'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='official_project_documents',
|
||||
field=models.FileField(blank=True, default=None, help_text='Attach any legal or official documents that relate to the project.', null=True, upload_to='', verbose_name='Official project documents'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='other_documents',
|
||||
field=models.FileField(blank=True, default=None, help_text='Attach any other documents that relate to the project.', null=True, upload_to='', verbose_name='Other documents'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='shown_on_other_platforms',
|
||||
field=models.NullBooleanField(default=None, help_text='Tick the box if you would like us to show this case study on other social media platforms', verbose_name='Show on other platforms?'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='casestudy',
|
||||
name='shown_on_other_platforms_detail',
|
||||
field=models.CharField(blank=True, help_text='List the social media platforms that you would like us to specifically publish the case study on', max_length=128, null=True, verbose_name='Show on other platforms - Detail'),
|
||||
),
|
||||
]
|
@ -1,9 +1,12 @@
|
||||
import datetime
|
||||
from urllib import parse
|
||||
from django.contrib.gis.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django_extensions.db.fields import AutoSlugField
|
||||
from django_countries.fields import CountryField
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.template.defaultfilters import slugify
|
||||
from . import validators
|
||||
|
||||
|
||||
class CaseStudy(models.Model):
|
||||
@ -58,6 +61,38 @@ class CaseStudy(models.Model):
|
||||
('PROJCD', _('Projected Project')),
|
||||
)
|
||||
|
||||
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'))
|
||||
)
|
||||
|
||||
# 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
|
||||
##
|
||||
@ -72,11 +107,16 @@ class CaseStudy(models.Model):
|
||||
)
|
||||
|
||||
# Date and time of submission
|
||||
date_created = models.DateTimeField(auto_now=True, null=False)
|
||||
date_created = models.DateTimeField(auto_now_add=True, null=False)
|
||||
|
||||
# Slug derived from entry_name, used in urls for SEO
|
||||
# TODO: Change this so it's not dynamic. Slugs should never change.
|
||||
slug = AutoSlugField(populate_from=['entry_name'])
|
||||
|
||||
##
|
||||
# First Screen
|
||||
##
|
||||
|
||||
# 1.1
|
||||
entry_name = models.CharField(
|
||||
verbose_name=_("Entry Name"),
|
||||
@ -86,7 +126,11 @@ class CaseStudy(models.Model):
|
||||
)
|
||||
|
||||
# N/A - Not explicitly listed in spec
|
||||
location = models.PointField()
|
||||
location = models.PointField(
|
||||
verbose_name=_("Project location"),
|
||||
help_text=_("Place a marker using the tools on the left of the map. Zoom in as far as you can so the placement \
|
||||
is accurate (important)")
|
||||
)
|
||||
|
||||
# 1.2
|
||||
sector_of_economy = models.CharField(
|
||||
@ -106,7 +150,10 @@ class CaseStudy(models.Model):
|
||||
)
|
||||
|
||||
# 1.4
|
||||
country = CountryField()
|
||||
country = CountryField(
|
||||
verbose_name=_("Country field"),
|
||||
help_text=_("Select the country of the project")
|
||||
)
|
||||
|
||||
# 1.5.1
|
||||
area_of_land = models.IntegerField(
|
||||
@ -125,9 +172,10 @@ class CaseStudy(models.Model):
|
||||
# 1.5.3
|
||||
land_ownership_details = models.CharField(
|
||||
verbose_name=_("Land ownership details"),
|
||||
help_text=_("Add any details and other remarks about the land\
|
||||
ownership"),
|
||||
max_length=256
|
||||
help_text=_("Please specify details about land ownership if you chose 'other'"),
|
||||
max_length=256,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
# 1.5.4
|
||||
@ -157,7 +205,7 @@ class CaseStudy(models.Model):
|
||||
# 1.5.6
|
||||
affects_indigenous = models.BooleanField(
|
||||
verbose_name=_("Affects indigenous people?"),
|
||||
help_text=_("Does the project affect indigenous people?")
|
||||
help_text=_("Does the project affect indigenous communities?")
|
||||
)
|
||||
|
||||
# 1.5.6.1
|
||||
@ -165,7 +213,10 @@ class CaseStudy(models.Model):
|
||||
verbose_name=_("Affects Indigenous - Details"),
|
||||
help_text=_("What group of indigenous people does the community belong\
|
||||
to?"),
|
||||
max_length=256
|
||||
max_length=256,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 1.6
|
||||
@ -176,6 +227,28 @@ class CaseStudy(models.Model):
|
||||
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"),
|
||||
@ -193,24 +266,287 @@ class CaseStudy(models.Model):
|
||||
here.")
|
||||
)
|
||||
|
||||
# 1.15
|
||||
# 1.11
|
||||
project_owners = models.CharField(
|
||||
verbose_name=_("Project and facility owners"),
|
||||
help_text=_("List companies or organisations that own the project and/or facilities. Separate with a comma."),
|
||||
max_length=120,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 1.12
|
||||
shareholders = models.CharField(
|
||||
verbose_name=_("Shareholders of the project owners"),
|
||||
help_text=_("List shareholders of the project owners you've just listed. Separate with a comma."),
|
||||
max_length=120,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 1.13
|
||||
financial_institutions = models.CharField(
|
||||
verbose_name=_("Financial institutions"),
|
||||
help_text=_("List banks and other financial institutions that have or are considering extending loans \
|
||||
or guarantees to the project. Separate with a comma."),
|
||||
max_length=120,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 1.14
|
||||
energy_customers = models.CharField(
|
||||
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."),
|
||||
max_length=120,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 1.15.1
|
||||
image = models.ImageField(
|
||||
verbose_name=_("Image")
|
||||
)
|
||||
|
||||
# 1.16
|
||||
video = models.URLField(
|
||||
verbose_name=_("Video"),
|
||||
max_length=43
|
||||
# 1.15.2
|
||||
image_caption = models.CharField(
|
||||
verbose_name=_("Image caption"),
|
||||
max_length=500,
|
||||
default=None,
|
||||
null=True,
|
||||
)
|
||||
|
||||
# 1.18
|
||||
# 1.15.3
|
||||
image_credit = models.CharField(
|
||||
verbose_name=_("Image credit(s)"),
|
||||
max_length=200,
|
||||
default=None,
|
||||
null=True,
|
||||
)
|
||||
|
||||
# 1.16.1
|
||||
video = models.URLField(
|
||||
verbose_name=_("YouTube Video"),
|
||||
help_text=_("Copy the URL to a related YouTube™ video that relates to the case study."),
|
||||
max_length=43,
|
||||
validators=[validators.YoutubeURLValidator()]
|
||||
)
|
||||
|
||||
# 1.16.2
|
||||
video_caption = models.CharField(
|
||||
verbose_name=_("Video caption"),
|
||||
max_length=500,
|
||||
default=None,
|
||||
null=True,
|
||||
)
|
||||
|
||||
# 1.16.3
|
||||
video_credit = models.CharField(
|
||||
verbose_name=_("Video credit(s)"),
|
||||
max_length=500,
|
||||
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."),
|
||||
max_length=500,
|
||||
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."),
|
||||
max_length=500,
|
||||
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\
|
||||
help_text=_("Add any direct quotes from members of the community that \
|
||||
relate to this project")
|
||||
)
|
||||
|
||||
# 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."),
|
||||
max_length=500,
|
||||
default=None,
|
||||
null=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
|
||||
##
|
||||
|
||||
# 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=_("Generation technology detail"),
|
||||
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 - autocomplete_light queryset
|
||||
|
||||
# 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.CharField(
|
||||
verbose_name=_("Additional technical or economic details"),
|
||||
help_text=_("Specify any additional technical or economic details relating to the project."),
|
||||
max_length=500,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 2.2 - Only if 1.2.2 selected
|
||||
# 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
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
energy_storage_capacity = models.IntegerField(
|
||||
verbose_name=_("Energy storage capacity"),
|
||||
help_text=_("Enter the total capacity of the energy storage system."),
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
##
|
||||
# Third Screen
|
||||
##
|
||||
|
||||
##
|
||||
# Fourth Screen
|
||||
##
|
||||
|
||||
# 4.1
|
||||
official_project_documents = models.FileField(
|
||||
verbose_name=_("Official project documents"),
|
||||
help_text=_("Attach any legal or official documents that relate to the project."),
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 4.2
|
||||
other_documents = models.FileField(
|
||||
verbose_name=_("Other documents"),
|
||||
help_text=_("Attach any other documents that relate to the project."),
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 4.3
|
||||
definition_of_affected_territories = models.CharField(
|
||||
verbose_name=_("Definition of affected territories"),
|
||||
help_text=_("In your own words, define the territories that the project will affect."),
|
||||
max_length=512,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 4.4
|
||||
shown_on_other_platforms = models.NullBooleanField(
|
||||
verbose_name=_("Show on other platforms?"),
|
||||
help_text=_("Tick the box if you would like us to show this case study on other social media platforms"),
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# 4.4.1
|
||||
shown_on_other_platforms_detail = models.CharField(
|
||||
verbose_name=_("Show on other platforms - Detail"),
|
||||
help_text=_("List the social media platforms that you would like us to specifically publish the case study on"),
|
||||
max_length=128,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
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)
|
||||
@ -227,3 +563,7 @@ class CaseStudy(models.Model):
|
||||
self.slug = slugify(self.entry_name)
|
||||
# Continue normal save method by calling original save method.
|
||||
super(CaseStudy, self).save(*args, **kwargs)
|
||||
|
||||
def get_video_id(self):
|
||||
"""Gets the 11 character YouTube video ID from the video field."""
|
||||
return parse.parse_qs(parse.urlparse(self.video).query)["v"][0]
|
||||
|
@ -1,4 +1,10 @@
|
||||
from moderation import moderation
|
||||
from moderation.moderator import GenericModerator
|
||||
from apps.map.models import CaseStudy
|
||||
|
||||
moderation.register(CaseStudy) # Uses default moderation settings
|
||||
|
||||
class CaseStudyModerator(GenericModerator):
|
||||
notify_user = True
|
||||
auto_approve_for_superusers = True
|
||||
|
||||
moderation.register(CaseStudy, CaseStudyModerator)
|
@ -17,7 +17,7 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row" style="background-color: #e3f3fd;">
|
||||
<div class="col-lg-8 border-top-0">
|
||||
<a class="btn btn-info" style="margin:15px 0;padding-left:20px;left:-10px;position:absolute;" href="{% url 'index' %}" role="button"><- {% trans "Back to Map" %}</a>
|
||||
<a class="btn btn-info" style="margin:15px 0;padding-left:20px;left:-10px;position:absolute;" href="{% url 'index' %}" role="button"><i class="fa fa-arrow-left" aria-hidden="true"></i> {% trans "Back to Map" %}</a>
|
||||
<div style="margin-top:70px;padding:0 20px;">
|
||||
<h1>{{case_study.entry_name}}</h1>
|
||||
<p>{{case_study.synopsis}}</p>
|
||||
@ -33,13 +33,13 @@
|
||||
<span class="badge badge-pill bg-info">{{case_study.country.name}}</span>
|
||||
</br>
|
||||
<small class="text-muted">Created {{case_study.date_created|naturaltime}} by <i>{{case_study.author.}}</i></small>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-primary btn-lg float-right" href="#" role="button">Get Involved</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="embed-responsive embed-responsive-16by9">
|
||||
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/ScMzIvxBSi4?rel=0&showinfo=0" frameborder="0" allowfullscreen></iframe>
|
||||
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/{{case_study.get_video_id}}?rel=0&showinfo=0" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -31,4 +31,95 @@
|
||||
// See GeometryField source (static/leaflet/leaflet.forms.js) to override more stuff...
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Conditional logic for hiding and un-hiding fields. -->
|
||||
<script type="text/javascript">
|
||||
// Here we define the fields we need to conditionally toggle.
|
||||
// TODO: Move this knowledge out of the template
|
||||
var conditionalFields = [{
|
||||
"field": "#id_land_ownership",
|
||||
"showHide": ["#div_id_land_ownership_details"],
|
||||
"condition": "OTH"
|
||||
},
|
||||
{
|
||||
"field": "#id_power_technology",
|
||||
"showHide": ["#div_id_power_technology_other"],
|
||||
"condition": "OT"
|
||||
},
|
||||
{
|
||||
"field": "#id_sector_of_economy",
|
||||
"showHide": ["#div_id_generation_technology",
|
||||
"#div_id_biomass_detail",
|
||||
"#div_id_generation_technology_other",
|
||||
"#div_id_total_generation_capacity",
|
||||
"#div_id_total_investment",
|
||||
"#div_id_technical_or_economic_details"],
|
||||
"condition": ["WND","SOL","HYD"]
|
||||
}];
|
||||
|
||||
|
||||
|
||||
|
||||
// Here we define the checkboxes that we need to use to
|
||||
// conditionally toggle fields - they use slightly different
|
||||
// logic as they rely on the 'checked' attribute rather than value.
|
||||
var conditionalCheckboxes = [{
|
||||
"checkbox": "#id_affects_indigenous",
|
||||
"showHide": "#div_id_affects_indigenous_detail"
|
||||
}];
|
||||
|
||||
// Define a function that hides the field and then creates a listener to toggle the field.
|
||||
// Takes a single conditionalField dictionary with (field, showHide and condition).
|
||||
function addConditionalField(item) {
|
||||
hideAll(item.showHide);
|
||||
$(item.field).change(function(){
|
||||
// Get the value of the option
|
||||
var value = $(this).val();
|
||||
|
||||
// Check the value matches any of the conditions.
|
||||
if (isInArray(value, item.condition)){
|
||||
showAll(item.showHide);
|
||||
} else {
|
||||
hideAll(item.showHide);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// This function does the same as addConditionalField except it checks the status of
|
||||
// checkboxes instead of fields.
|
||||
function addConditionalCheckbox(item) {
|
||||
$(item.showHide).hide();
|
||||
$(item.checkbox).change(function(){
|
||||
if ($(this).is(":checked")) {
|
||||
$(item.showHide).show();
|
||||
} else {
|
||||
$(item.showHide).hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
function show(tag) {
|
||||
$(tag).show();
|
||||
}
|
||||
|
||||
function hide(tag) {
|
||||
$(tag).hide();
|
||||
}
|
||||
|
||||
function showAll(tags) {
|
||||
tags.forEach(show);
|
||||
}
|
||||
|
||||
function hideAll(tags) {
|
||||
tags.forEach(hide);
|
||||
}
|
||||
|
||||
function isInArray(value, array) {
|
||||
return array.indexOf(value) > -1;
|
||||
}
|
||||
|
||||
conditionalFields.forEach(addConditionalField);
|
||||
conditionalCheckboxes.forEach(addConditionalCheckbox);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -100,13 +100,13 @@
|
||||
}).addTo(map);
|
||||
});
|
||||
|
||||
// Add an on-click listener for map click events. Show popup with button to submit a casestudy
|
||||
map.on('click', function(e) {
|
||||
var popup = L.popup()
|
||||
.setLatLng(e.latlng)
|
||||
.setContent("<a class='btn btn-primary btn-sm' href='{% url 'create' %}?lat="+e.latlng.lat+"&lng="+e.latlng.lng+"' role='button'>{% trans "Submit a Case Study" %}</a>")
|
||||
.openOn(map);
|
||||
});
|
||||
<!--// Add an on-click listener for map click events. Show popup with button to submit a casestudy-->
|
||||
<!--map.on('click', function(e) {-->
|
||||
<!--var popup = L.popup()-->
|
||||
<!--.setLatLng(e.latlng)-->
|
||||
<!--.setContent("<a class='btn btn-primary btn-sm' href='{% url 'create' %}?lat="+e.latlng.lat+"&lng="+e.latlng.lng+"' role='button'>{% trans "Submit a Case Study" %}</a>")-->
|
||||
<!--.openOn(map);-->
|
||||
<!--});-->
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
5
apps/map/validators.py
Normal file
5
apps/map/validators.py
Normal file
@ -0,0 +1,5 @@
|
||||
from django.core.validators import RegexValidator
|
||||
|
||||
|
||||
class YoutubeURLValidator(RegexValidator):
|
||||
regex = r'https?:\/\/(((www.)?youtube.com\/((watch\?v=)|(watch\/)))|(youtu.be\/))([A-z0-9]{1,11}).+'
|
7
apps/profiles/forms.py
Normal file
7
apps/profiles/forms.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.forms import ModelForm
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
|
||||
class UpdateProfile(ModelForm):
|
||||
class Meta:
|
||||
model = get_user_model()
|
@ -1,2 +1,6 @@
|
||||
{% extends "base_page.html" %}
|
||||
Profile page
|
||||
Profile page
|
||||
<form action="" method="post">{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="Update" />
|
||||
</form>
|
@ -3,5 +3,19 @@ from django.conf.urls import url
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.Profile.as_view(), name='profile'),
|
||||
]
|
||||
url(
|
||||
regex=r'^~redirect/$',
|
||||
view=views.UserRedirectView.as_view(),
|
||||
name='redirect'
|
||||
),
|
||||
url(
|
||||
regex=r'^$',
|
||||
view=views.UserDetailView.as_view(),
|
||||
name='detail'
|
||||
),
|
||||
url(
|
||||
regex=r'^~update/$',
|
||||
view=views.UserUpdateView.as_view(),
|
||||
name='update'
|
||||
),
|
||||
]
|
@ -1,5 +1,46 @@
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
|
||||
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
|
||||
class Profile(TemplateView):
|
||||
template_name = "profiles/profile.html"
|
||||
class UserDetailView(LoginRequiredMixin, DetailView):
|
||||
model = get_user_model()
|
||||
# These next two lines tell the view to index lookups by username
|
||||
slug_field = 'username'
|
||||
slug_url_kwarg = 'username'
|
||||
|
||||
def get_object(self):
|
||||
return get_user_model().objects.get(username=self.request.user.username)
|
||||
|
||||
|
||||
class UserRedirectView(LoginRequiredMixin, RedirectView):
|
||||
permanent = False
|
||||
|
||||
def get_redirect_url(self):
|
||||
return reverse('profile:detail')
|
||||
|
||||
|
||||
class UserUpdateView(LoginRequiredMixin, UpdateView):
|
||||
|
||||
fields = ['first_name', 'last_name']
|
||||
|
||||
# we already imported User in the view code above, remember?
|
||||
model = get_user_model()
|
||||
|
||||
# send the user back to their own page after a successful update
|
||||
def get_success_url(self):
|
||||
return reverse('profile:detail')
|
||||
|
||||
def get_object(self):
|
||||
# Only get the User record for the user making the request
|
||||
return get_user_model().objects.get(username=self.request.user.username)
|
||||
|
||||
|
||||
class UserListView(LoginRequiredMixin, ListView):
|
||||
model = get_user_model()
|
||||
# These next two lines tell the view to index lookups by username
|
||||
slug_field = 'username'
|
||||
slug_url_kwarg = 'username'
|
||||
|
@ -16,6 +16,7 @@ services:
|
||||
volumes:
|
||||
- ./apps:/app/apps
|
||||
- ./ojusomap:/app/ojusomap
|
||||
- ./support:/app/support
|
||||
- /containers/map/static:/app/static
|
||||
- /containers/map/gunicorn.sock:/app/gunicorn.sock
|
||||
env_file:
|
||||
|
@ -30,7 +30,10 @@ SECRET_KEY = os.getenv(
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = bool(int(os.getenv('DEBUG', False)))
|
||||
|
||||
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost').split()
|
||||
if DEBUG:
|
||||
ALLOWED_HOSTS = ['*']
|
||||
else:
|
||||
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost').split()
|
||||
|
||||
|
||||
# Application definition
|
||||
@ -51,6 +54,7 @@ INSTALLED_APPS = [
|
||||
'whitenoise.runserver_nostatic',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.gis',
|
||||
'avatar',
|
||||
'bootstrap3',
|
||||
'cas_server',
|
||||
'compressor',
|
||||
@ -62,6 +66,7 @@ INSTALLED_APPS = [
|
||||
'raven.contrib.django.raven_compat',
|
||||
'rest_framework',
|
||||
'rest_framework_gis',
|
||||
'storages'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -174,6 +179,16 @@ LOCALE_PATHS = [
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
||||
|
||||
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
|
||||
|
||||
AWS_S3_ENDPOINT_URL = "https://ojuso-media.nyc3.digitaloceanspaces.com"
|
||||
AWS_STORAGE_BUCKET_NAME = "ojuso-media"
|
||||
AWS_LOCATION = ""
|
||||
AWS_S3_REGION_NAME = "nyc3"
|
||||
AWS_S3_CUSTOM_DOMAIN = "ojuso-media.nyc3.digitaloceanspaces.com/ojuso-media"
|
||||
AWS_ACCESS_KEY_ID = "RUZTFVKPCNJIWCVUVJFW"
|
||||
AWS_SECRET_ACCESS_KEY = "pTZAnmtvGzFBdI/jwtwRoFW5eK7eJ8FLFxr1/Jb+Yq4"
|
||||
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
|
||||
STATIC_URL = os.getenv("STATIC_URL", '/static/')
|
||||
STATICFILES_FINDERS = [
|
||||
@ -184,7 +199,7 @@ STATICFILES_FINDERS = [
|
||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
|
||||
MEDIA_URL = os.getenv("MEDIA_URL", '/media/')
|
||||
MEDIA_URL = os.getenv("MEDIA_URL", "https://ojuso-media.nyc3.digitaloceanspaces.com/ojuso-media/")
|
||||
|
||||
# Cache
|
||||
# https://docs.djangoproject.com/en/1.11/topics/cache/
|
||||
@ -248,3 +263,13 @@ RAVEN_CONFIG = {
|
||||
# release based on the git info.
|
||||
'release': raven.fetch_git_sha(os.path.dirname(os.pardir)),
|
||||
}
|
||||
|
||||
# Avatars
|
||||
AVATAR_GRAVATAR_DEFAULT = "mm"
|
||||
AVATAR_CLEANUP_DELETED = True
|
||||
|
||||
# Messages
|
||||
from django.contrib.messages import constants as messages
|
||||
MESSAGE_TAGS = {
|
||||
messages.ERROR: 'danger'
|
||||
}
|
36
ojusomap/templates/auth/user_detail.html
Normal file
36
ojusomap/templates/auth/user_detail.html
Normal file
@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}User: {{ object.username }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
|
||||
<h2>{{ object.username }}</h2>
|
||||
{% if object.name %}
|
||||
<p>{{ object.name }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if object == request.user %}
|
||||
<!-- Action buttons -->
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<a class="btn btn-primary" href="{% url 'profile:update' %}" role="button">{% trans 'Change Name' %}</a>
|
||||
<a class="btn btn-primary" href="" role="button">E-Mail</a>
|
||||
<!-- Your Stuff: Custom user template urls -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- End Action buttons -->
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
17
ojusomap/templates/auth/user_form.html
Normal file
17
ojusomap/templates/auth/user_form.html
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block title %}{{ user.username }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ user.username }}</h1>
|
||||
<form class="form-horizontal" method="post" action="{% url 'profile:update' %}">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<button type="submit" class="btn">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
17
ojusomap/templates/auth/user_list.html
Normal file
17
ojusomap/templates/auth/user_list.html
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static i18n %}
|
||||
{% block title %}Members{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<h2>Users</h2>
|
||||
|
||||
<div class="list-group">
|
||||
{% for user in user_list %}
|
||||
<a href="" class="list-group-item">
|
||||
<h4 class="list-group-item-heading">{{ user.username }}</h4>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
@ -1,4 +1,5 @@
|
||||
{% spaceless %}
|
||||
{% load avatar_tags %}
|
||||
{% load flatpages %}
|
||||
{% load i18n %}
|
||||
{% load leaflet_tags %}
|
||||
@ -10,7 +11,9 @@
|
||||
<meta charset="utf-8">
|
||||
<title>{% block page_title %}Ojuso{% endblock %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<script src="{% static 'map/bundle.js'%}"></script>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous"></script>
|
||||
<!--{# <script src="{% static 'map/bundle.js'%}"></script> #}-->
|
||||
|
||||
{# Additional Stylesheets #}
|
||||
{% block stylesheets %}
|
||||
@ -22,42 +25,68 @@
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="{% url 'index' %}">
|
||||
<img src="{% static 'map/images/ojuso-logo-black.png' %}" height="40px"/>
|
||||
<img src="{% static 'map/images/ojuso-logo-black.png' %}" height="20px"/>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Map <span class="sr-only">(current)</span></a>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'index' %}">{% trans 'Map' %}<span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
{% get_flatpages as flatpages %}
|
||||
{% for page in flatpages %}
|
||||
<li class="nav-item"><a class="nav-link" href="{{page.url}}">{{page.title}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul class="navbar-nav my-2 my-lg-0">
|
||||
{% if user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
<a class="btn btn-outline-info" href="{% url 'create' %}"><i class="fa fa-plus" aria-hidden="true"> New Case Study</i></a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a style="margin:-10px 0 -10px 0" class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<img src="{% avatar_url user %}" class="rounded-circle" width="40" height="40" style="position:relative;margin-right:5px"/><span>{{user}}</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right" style="padding-bottom:0px" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item" href="{% url 'avatar_change' %}"><i class="fa fa-cog" aria-hidden="true"></i> Change Avatar</a>
|
||||
<a class="dropdown-item" href="{% url 'profile:detail' %}"><i class="fa fa-cog" aria-hidden="true"></i> Profile</a>
|
||||
<div class="dropdown-divider" style="margin-bottom:0px"></div>
|
||||
<a class="dropdown-item bg-danger" style="color:white;padding:0.5rem 1.5rem" href="{% url 'auth_logout' %}"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> {% trans 'Logout' %}</a>
|
||||
</div>
|
||||
</li>
|
||||
{% get_flatpages as flatpages %}
|
||||
{% for page in flatpages %}
|
||||
<li class="nav-item"><a class="nav-link" href="{{page.url}}">{{page.title}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% else %}
|
||||
<li class="nav-item"><a style="margin: 5px;" class="btn btn-outline-primary" href={% url 'auth_login' %}>{% trans 'Login' %}</a></li>
|
||||
<li class="nav-item"><a style="margin: 5px;" class="btn btn-info" href={% url 'registration_register' %}>{% trans 'Register' %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% if user.is_authenticated %}
|
||||
<span>{{user}}</span>
|
||||
<a class="btn btn-primary" href={% url 'auth_logout' %}>Logout</a>
|
||||
{% else %}
|
||||
<a style="margin: 5px;" class="btn btn-primary" href={% url 'auth_login' %}>Login</a>
|
||||
<a style="margin: 5px;" class="btn btn-info" href={% url 'registration_register' %}>Register</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</nav>
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
|
||||
{# CDN Javascript #}
|
||||
<script src="//code.jquery.com/jquery-3.2.1.min.js"
|
||||
integrity="sha384-xBuQ/xzmlsLoJpyjoggmTEz8OWUFM0/RC5BsqQBDX2v5cMvDHcMakNTNrHIW2I5f"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="//code.jquery.com/jquery-3.2.1.min.js" integrity="sha384-xBuQ/xzmlsLoJpyjoggmTEz8OWUFM0/RC5BsqQBDX2v5cMvDHcMakNTNrHIW2I5f" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</html>
|
||||
{% endspaceless %}
|
||||
|
@ -1,10 +1,9 @@
|
||||
{% extends 'base_email.html' %}
|
||||
{% block content %}
|
||||
<div align="left">
|
||||
{{user}},<br><br>
|
||||
To activate your account and log in, <a href="https://animalrightsmap.org{% url 'registration_activate' activation_key %}">click here</a>.<br>
|
||||
This link will expire in 7 days so be sure do it soon.<br><br>
|
||||
See you on the activist trail!<br><br>
|
||||
- Animal Rights Map
|
||||
{{user}},<br><br>
|
||||
To activate your account and log in, <a href="https://animalrightsmap.org{% url 'registration_activate' activation_key %}">click here</a>.<br>
|
||||
This link will expire in 7 days so be sure do it soon.<br><br>
|
||||
- Ojuso
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -9,8 +9,8 @@
|
||||
{% block content %}
|
||||
<div class="container" style="max-width:520px;">
|
||||
<div class="page-lead">
|
||||
<h2>Login</h2>
|
||||
<p class="lead">{% trans "Welcome!" %}</p>
|
||||
<h2>{% trans 'Login' %}</h2>
|
||||
<p class="lead">{% trans 'Welcome!' %}</p>
|
||||
</div>
|
||||
{% bootstrap_messages %}
|
||||
<form action="{% url 'auth_login' %}?next={{next}}" method="post">
|
||||
|
@ -2,21 +2,22 @@
|
||||
{% load bootstrap3 %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load envelope_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page_name %}Registration{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container" style="max-width:520px;">
|
||||
<div class="page-lead">
|
||||
<h2>Registration</h2>
|
||||
<p class="lead">Create your account and get active!</p>
|
||||
<h2>{% trans 'Registration' %}</h2>
|
||||
<p class="lead">{% trans 'Create your account and get active!' %}</p>
|
||||
</div>
|
||||
{% bootstrap_messages %}
|
||||
<form action="{% url 'registration_register' %}" method="post">
|
||||
{% csrf_token %}
|
||||
{% antispam_fields %}
|
||||
{{ form|crispy }}
|
||||
<input class="btn btn-success pull-right" type="submit" name"submit" value"Register"/>
|
||||
<input class="btn btn-success pull-right" type="submit" name="su/bmit" value="{% trans 'Register'%}"/>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -51,12 +51,13 @@ apirouter.register(r'case-studies', CaseStudyViewSet)
|
||||
urlpatterns = [
|
||||
url(r'api/', include(apirouter.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
url(r'^avatar/', include('avatar.urls')),
|
||||
url(r'^cas/', include('cas_server.urls', namespace='cas_server')),
|
||||
# url(r'^contact/', include('apps.contact.urls'), name="contact")
|
||||
# url(r'^contact/', include('apps.contact.urls'), name="contact"),
|
||||
]
|
||||
|
||||
urlpatterns += i18n_patterns(
|
||||
url(r'^accounts/profile/', include('apps.profiles.urls')),
|
||||
url(r'^accounts/profile/', include('apps.profiles.urls', namespace="profile")),
|
||||
# url(r'^accounts/logout/?$', include('django.contrib.auth.views.logout'), {'next_page': '/'}),
|
||||
url(r'^accounts/', include('registration.backends.default.urls')),
|
||||
url(r'', include('apps.map.urls'), name="map"),
|
||||
|
@ -1,7 +1,10 @@
|
||||
appdirs==1.4.3
|
||||
brotlipy==0.7.0
|
||||
boto==2.48.0
|
||||
boto3==1.4.7
|
||||
Django==1.11.6
|
||||
django-appconf==1.0.2
|
||||
django-avatar==4.0.1
|
||||
django-bootstrap3==8.2.3
|
||||
django-braces==1.11.0
|
||||
django-cas-server==0.8.0
|
||||
@ -15,6 +18,7 @@ django-geojson==2.10.0
|
||||
-e git://github.com/makinacorpus/django-leaflet.git@a43acc5fed6674b413a6fab0feeb7c44e67c2ca8#egg=django-leaflet
|
||||
django-moderation==0.5.0
|
||||
django-registration-redux==1.6
|
||||
django-storages==1.6.5
|
||||
djangorestframework==3.6.3
|
||||
djangorestframework-gis==0.11.2
|
||||
gunicorn==19.7.1
|
||||
|
Loading…
Reference in New Issue
Block a user