Add registration and login templates plus UI stuff, moderation

This commit is contained in:
Livvy Mackintosh 2017-10-08 21:21:51 +01:00
parent f8dc44b4a6
commit 049ca29e77
64 changed files with 18607 additions and 159 deletions

View File

@ -47,6 +47,8 @@ RUN wget https://nodejs.org/dist/v7.10.0/node-v7.10.0-linux-x64.tar.gz\
&& tar -xvf ../../proj-datumgrid-1.5.tar.gz && cd ../ \ && tar -xvf ../../proj-datumgrid-1.5.tar.gz && cd ../ \
&& ./configure && make && make install && ./configure && make && make install
RUN apt-get update && apt-get install -y gettext git
# PACKAGES # PACKAGES
WORKDIR /app WORKDIR /app
COPY ./requirements.txt . COPY ./requirements.txt .
@ -59,8 +61,6 @@ COPY ./support/cron/* /etc/cron.d/
RUN chmod 0644 /etc/cron.d/*\ RUN chmod 0644 /etc/cron.d/*\
&& touch /var/log/cron.log && touch /var/log/cron.log
RUN apt-get install -y gettext
EXPOSE 8000 EXPOSE 8000
CMD [ "python3", "manage.py", "migrate", "&&", \ CMD [ "python3", "manage.py", "migrate", "&&", \

0
apps/contact/__init__.py Normal file
View File

11
apps/contact/forms.py Normal file
View File

@ -0,0 +1,11 @@
from envelope.forms import ContactForm
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
class ContactForm(ContactForm):
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit('submit', 'Submit',
css_class='btn-lg pull-right'))

View File

@ -0,0 +1,21 @@
{% extends "base_page.html" %}
{% load bootstrap3 %}
{% load crispy_forms_tags %}
{% load envelope_tags %}
{% block page_name %}Contact{% endblock %}
{% block content %}
<div class="container">
<div class="page-lead">
<h2>Contact</h2>
<p class="lead">Send us your thoughts and feedback.</p>
</div>
{% bootstrap_messages %}
<form action="{% url 'contact' %}" method="post">
{% csrf_token %}
{% antispam_fields %}
{% crispy form %}
</form>
</div>
{% endblock %}

3
apps/contact/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

7
apps/contact/urls.py Normal file
View File

@ -0,0 +1,7 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.ContactView.as_view(), name='contact'),
]

12
apps/contact/views.py Normal file
View File

@ -0,0 +1,12 @@
from braces.views import FormMessagesMixin
from envelope.views import ContactView
from django.utils.translation import ugettext_lazy as _
from .forms import ContactForm
class ContactView(FormMessagesMixin, ContactView):
form_invalid_message = _(u"There was an error in the contact form.")
form_valid_message = _(u"Thank you for your message.")
form_class = ContactForm

View File

@ -1,6 +1,12 @@
from django.contrib import admin from django.contrib import admin
from moderation.admin import ModerationAdmin
from leaflet.admin import LeafletGeoAdmin from leaflet.admin import LeafletGeoAdmin
from .models import CaseStudy from .models import CaseStudy
admin.site.register(CaseStudy, LeafletGeoAdmin)
class CaseStudyAdmin(ModerationAdmin, LeafletGeoAdmin):
pass
admin.site.register(CaseStudy, CaseStudyAdmin)

View File

@ -6,15 +6,15 @@ from leaflet.forms.widgets import LeafletWidget
from .models import CaseStudy from .models import CaseStudy
class CaseStudyForm(forms.ModelForm): class BaseCaseStudyForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(CaseStudyForm, self).__init__(*args, **kwargs) super(BaseCaseStudyForm, self).__init__(*args, **kwargs)
self.helper = FormHelper() self.helper = FormHelper()
self.helper.form_id = 'case-study-form' self.helper.form_id = 'case-study-form'
self.helper.form_class = 'form-horizontal' self.helper.form_class = 'form-horizontal'
self.helper.form_method = 'post' self.helper.form_method = 'post'
self.helper.form_action = 'submit' self.helper.form_action = 'add'
self.helper.label_class = 'col-lg-2' self.helper.label_class = 'col-lg-2'
self.helper.field_class = 'col-lg-8' self.helper.field_class = 'col-lg-8'
self.helper.add_input(Submit('submit', 'Submit')) self.helper.add_input(Submit('submit', 'Submit'))
@ -22,4 +22,33 @@ class CaseStudyForm(forms.ModelForm):
class Meta: class Meta:
model = CaseStudy model = CaseStudy
fields = '__all__' fields = '__all__'
widgets = {'location': LeafletWidget()} widgets = {'location': LeafletWidget(attrs={})}
class ShortCaseStudyForm(BaseCaseStudyForm):
class Meta(BaseCaseStudyForm.Meta):
fields = [
'entry_name',
'location',
'sector_of_economy',
'positive_or_negative',
'country',
'area_of_land',
'land_ownership',
'land_ownership_details',
'location_context',
'type_of_ecosystem',
'describe_ecosystem',
'affects_indigenous',
'affects_indigenous_detail',
'project_status',
'synopsis',
'full_description',
'image',
'community_voices'
]
class LongCaseStudyForm(BaseCaseStudyForm):
class Meta(BaseCaseStudyForm.Meta):
fields = '__all__'

View File

@ -0,0 +1,169 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-10-06 15:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('map', '0003_auto_20170521_0643'),
]
operations = [
migrations.RemoveField(
model_name='casestudy',
name='affects_indigenous',
),
migrations.RemoveField(
model_name='casestudy',
name='affects_indigenous_reason',
),
migrations.RemoveField(
model_name='casestudy',
name='associated_companies',
),
migrations.RemoveField(
model_name='casestudy',
name='commodities',
),
migrations.RemoveField(
model_name='casestudy',
name='description',
),
migrations.RemoveField(
model_name='casestudy',
name='financiers',
),
migrations.RemoveField(
model_name='casestudy',
name='generation_type',
),
migrations.RemoveField(
model_name='casestudy',
name='important_lenders',
),
migrations.RemoveField(
model_name='casestudy',
name='like_to_engage_developer',
),
migrations.RemoveField(
model_name='casestudy',
name='like_to_engage_investors',
),
migrations.RemoveField(
model_name='casestudy',
name='link_to_forum',
),
migrations.RemoveField(
model_name='casestudy',
name='project_name',
),
migrations.RemoveField(
model_name='casestudy',
name='proposed_completion',
),
migrations.RemoveField(
model_name='casestudy',
name='proposed_start',
),
migrations.RemoveField(
model_name='casestudy',
name='references',
),
migrations.RemoveField(
model_name='casestudy',
name='supply_chain',
),
migrations.AddField(
model_name='casestudy',
name='Affects Indigenous - Details',
field=models.CharField(default='', help_text='What group of indigenous people does the community belong to?', max_length=256),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Affects indigenous people?',
field=models.BooleanField(default=False, help_text='Does the project affect indigenous people?'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Approximate land area',
field=models.IntegerField(default=0, help_text='The area of land covered by the project (in km²)'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Community Voices',
field=models.TextField(default='', help_text='Add any direct quotes from members of the community that relate to this project'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Describe the ecosystem',
field=models.CharField(default='', help_text='In your own words, add more detail about the ecosystem.', max_length=256),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Entry Name',
field=models.CharField(default='', help_text='Enter the name of the entry. This should usually be the name of project.', max_length=128),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Full Description',
field=models.TextField(default='', help_text='Describe the project in full. Separate paragraphs with a new line Please add as much detail as you feel is necessary here.'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Land ownership',
field=models.CharField(choices=[('PRI', 'Private Land'), ('PUB', 'Public Land'), ('COM', 'Community Land'), ('OTH', 'Other')], default='', help_text='What type of ownership does the land fall under?', max_length=3),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Land ownership details',
field=models.CharField(default='', help_text='Add any details and other remarks about the land ownership', max_length=256),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Location',
field=models.CharField(choices=[('RUR', 'Rural'), ('URB', 'Urban')], default=None, help_text='Select the context that is most applicable to this case study.', max_length=1),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Positive or negative?',
field=models.CharField(choices=[('POS', 'Positive'), ('NEG', 'Negative')], default=None, help_text='Is the case study a positive case or a negative case?', max_length=1),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Sector of economy',
field=models.CharField(choices=[('Renewable Energy Generation', (('WND', 'Wind'), ('SOL', 'Solar'), ('HYD', 'Hydro'))), ('PG', 'Power Grids'), ('SM', 'Supply of Minerals')], default=None, help_text='Which sector of the renewable energy economy is most relevant?', max_length=2),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Status of Project',
field=models.CharField(choices=[('EXSTNG', 'Existing Project'), ('UCONST', 'Under Construction'), ('PROJCD', 'Projected Project')], default=None, help_text='What is the status of the current project?', max_length=6),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Synopsis',
field=models.TextField(default=None, help_text='Briefly describe the project. This will be displayed at the top of the case study page. Maximum 500 chars (about 3½ tweets)', max_length=500),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='Type of ecosystem',
field=models.CharField(choices=[('Water Based', (('MARINE', 'Marine (e.g. Ocean, Sea)'), ('FRESH', 'Freshwater (e.g. Freshwater, Lake)'))), ('Land Based', (('FOREST', 'Forest/Jungle'), ('AGRI', 'Agricultural Land'), ('GRASS', 'Grassland'), ('DESERT', 'Desert (Tundra, Ice or Sand)'), ('WETLND', 'Wetland (Marsh, Mangrove, Peat Soil)'), ('URBAN', 'Urban')))], default=None, help_text='Select the most relevant type of ecosystem.', max_length=6),
preserve_default=False,
),
]

View File

@ -0,0 +1,165 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-10-06 20:33
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('map', '0004_auto_20171006_1559'),
]
operations = [
migrations.RemoveField(
model_name='casestudy',
name='Affects Indigenous - Details',
),
migrations.RemoveField(
model_name='casestudy',
name='Affects indigenous people?',
),
migrations.RemoveField(
model_name='casestudy',
name='Approximate land area',
),
migrations.RemoveField(
model_name='casestudy',
name='Community Voices',
),
migrations.RemoveField(
model_name='casestudy',
name='Describe the ecosystem',
),
migrations.RemoveField(
model_name='casestudy',
name='Entry Name',
),
migrations.RemoveField(
model_name='casestudy',
name='Full Description',
),
migrations.RemoveField(
model_name='casestudy',
name='Land ownership',
),
migrations.RemoveField(
model_name='casestudy',
name='Land ownership details',
),
migrations.RemoveField(
model_name='casestudy',
name='Location',
),
migrations.RemoveField(
model_name='casestudy',
name='Positive or negative?',
),
migrations.RemoveField(
model_name='casestudy',
name='Sector of economy',
),
migrations.RemoveField(
model_name='casestudy',
name='Status of Project',
),
migrations.RemoveField(
model_name='casestudy',
name='Synopsis',
),
migrations.RemoveField(
model_name='casestudy',
name='Type of ecosystem',
),
migrations.AddField(
model_name='casestudy',
name='affects_indigenous',
field=models.BooleanField(default=None, help_text='Does the project affect indigenous people?', verbose_name='Affects indigenous people?'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='affects_indigenous_detail',
field=models.CharField(default=None, help_text='What group of indigenous people does the community belong to?', max_length=256, verbose_name='Affects Indigenous - Details'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='area_of_land',
field=models.IntegerField(default=None, help_text='The area of land covered by the project (in km²)', verbose_name='Approximate land area'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='community_voices',
field=models.TextField(default=None, help_text='Add any direct quotes from members of the community that relate to this project', verbose_name='Community Voices'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='describe_ecosystem',
field=models.CharField(default=None, help_text='In your own words, add more detail about the ecosystem.', max_length=256, verbose_name='Describe the ecosystem'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='entry_name',
field=models.CharField(default=None, help_text='Enter the name of the entry. This should usually be the name of project.', max_length=128, verbose_name='Entry Name'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='full_description',
field=models.TextField(default=None, help_text='Describe the project in full. Separate paragraphs with a new line Please add as much detail as you feel is necessary here.', verbose_name='Full Description'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='land_ownership',
field=models.CharField(choices=[('PRI', 'Private Land'), ('PUB', 'Public Land'), ('COM', 'Community Land'), ('OTH', 'Other')], default=None, help_text='What type of ownership does the land fall under?', max_length=3, verbose_name='Land ownership'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='land_ownership_details',
field=models.CharField(default=None, help_text='Add any details and other remarks about the land ownership', max_length=256, verbose_name='Land ownership details'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='location_context',
field=models.CharField(choices=[('RUR', 'Rural'), ('URB', 'Urban')], default=None, help_text='Select the context that is most applicable to this case study.', max_length=1, verbose_name='Location'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='positive_or_negative',
field=models.CharField(choices=[('POS', 'Positive'), ('NEG', 'Negative')], default=None, help_text='Is the case study a positive case or a negative case?', max_length=1, verbose_name='Positive or negative?'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='project_status',
field=models.CharField(choices=[('EXSTNG', 'Existing Project'), ('UCONST', 'Under Construction'), ('PROJCD', 'Projected Project')], default=None, help_text='What is the status of the current project?', max_length=6, verbose_name='Status of Project'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='sector_of_economy',
field=models.CharField(choices=[('Renewable Energy Generation', (('WND', 'Wind'), ('SOL', 'Solar'), ('HYD', 'Hydro'))), ('PG', 'Power Grids'), ('SM', 'Supply of Minerals')], default=None, help_text='Which sector of the renewable energy economy is most relevant?', max_length=2, verbose_name='Sector of economy'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='synopsis',
field=models.TextField(default=None, help_text='Briefly describe the project. This will be displayed at the top of the case study page. Maximum 500 chars (about 3½ tweets)', max_length=500, verbose_name='Synopsis'),
preserve_default=False,
),
migrations.AddField(
model_name='casestudy',
name='type_of_ecosystem',
field=models.CharField(choices=[('Water Based', (('MARINE', 'Marine (e.g. Ocean, Sea)'), ('FRESH', 'Freshwater (e.g. Freshwater, Lake)'))), ('Land Based', (('FOREST', 'Forest/Jungle'), ('AGRI', 'Agricultural Land'), ('GRASS', 'Grassland'), ('DESERT', 'Desert (Tundra, Ice or Sand)'), ('WETLND', 'Wetland (Marsh, Mangrove, Peat Soil)'), ('URBAN', 'Urban')))], default=None, help_text='Select the most relevant type of ecosystem.', max_length=6, verbose_name='Type of ecosystem'),
preserve_default=False,
),
]

View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-10-07 13:49
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('map', '0005_auto_20171006_2033'),
]
operations = [
migrations.AlterField(
model_name='casestudy',
name='location_context',
field=models.CharField(choices=[('RUR', 'Rural'), ('URB', 'Urban')], help_text='Select the context that is most applicable to this case study.', max_length=3, verbose_name='Location'),
),
migrations.AlterField(
model_name='casestudy',
name='positive_or_negative',
field=models.CharField(choices=[('P', 'Positive'), ('N', 'Negative')], help_text='Is the case study a positive case or a negative case?', max_length=1, verbose_name='Positive or negative?'),
),
migrations.AlterField(
model_name='casestudy',
name='sector_of_economy',
field=models.CharField(choices=[('Renewable Energy Generation', (('WND', 'Wind'), ('SOL', 'Solar'), ('HYD', 'Hydro'))), ('PG', 'Power Grids'), ('SM', 'Supply of Minerals')], help_text='Which sector of the renewable energy economy is most relevant?', max_length=3, verbose_name='Sector of economy'),
),
]

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-10-07 14:23
from __future__ import unicode_literals
from django.db import migrations
import django_extensions.db.fields
class Migration(migrations.Migration):
dependencies = [
('map', '0006_auto_20171007_1349'),
]
operations = [
migrations.AddField(
model_name='casestudy',
name='slug',
field=django_extensions.db.fields.AutoSlugField(blank=True, editable=False, populate_from=['entry_name']),
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-10-07 15:02
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('map', '0007_casestudy_slug'),
]
operations = [
migrations.AddField(
model_name='casestudy',
name='date_created',
field=models.DateTimeField(auto_now=True),
),
]

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-10-07 15:44
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('map', '0008_casestudy_date_created'),
]
operations = [
migrations.AddField(
model_name='casestudy',
name='video',
field=models.URLField(default="", max_length=43, verbose_name='Video'),
preserve_default=False,
),
migrations.AlterField(
model_name='casestudy',
name='image',
field=models.ImageField(upload_to='', verbose_name='Image'),
),
]

View File

@ -1,21 +1,67 @@
from django.contrib.gis.db import models from django.contrib.gis.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django_extensions.db.fields import AutoSlugField
from django_countries.fields import CountryField from django_countries.fields import CountryField
from django.utils.translation import ugettext as _
from django.template.defaultfilters import slugify
class CaseStudy(models.Model): class CaseStudy(models.Model):
"""Model for case studies submitted to the Ojuso Platform""" """Model for case studies submitted to the Ojuso Platform"""
# Choice lists for dropdowns # Choice lists for drop-downs
SUPPLY_CHAIN_CHOICES = ( SECTOR_CHOICES = (
('A', 'Option A'), (_('Renewable Energy Generation'), (
('B', 'Option B'), ('WND', _('Wind')),
('SOL', _('Solar')),
('HYD', _('Hydro')),
)),
('PG', _('Power Grids')),
('SM', _('Supply of Minerals')),
) )
GENERATION_TYPE_CHOICES = (
('W', 'Wind'), POSITIVE_NEGATIVE_CHOICES = (
('S', 'Solar'), ('P', _('Positive')),
('N', _('Negative'))
) )
LAND_OWNERSHIP_CHOICES = (
('PRI', _('Private Land')),
('PUB', _('Public Land')),
('COM', _('Community Land')),
('OTH', _('Other')),
)
LOCATION_CONTEXT_CHOICES = (
('RUR', _('Rural')),
('URB', _('Urban')),
)
TYPE_OF_ECOSYSTEM_CHOICES = (
(_('Water Based'), (
('MARINE', _('Marine (e.g. Ocean, Sea)')),
('FRESH', _('Freshwater (e.g. Freshwater, Lake)')),
)),
(_('Land Based'), (
('FOREST', _('Forest/Jungle')),
('AGRI', _('Agricultural Land')),
('GRASS', _('Grassland')),
('DESERT', _('Desert (Tundra, Ice or Sand)')),
('WETLND', _('Wetland (Marsh, Mangrove, Peat Soil)')),
('URBAN', _('Urban')),
))
)
PROJECT_STATUS_CHOICES = (
('EXSTNG', _('Existing Project')),
('UCONST', _('Under Construction')),
('PROJCD', _('Projected Project')),
)
##
# Meta Fields
##
# User who submitted case study # User who submitted case study
author = models.ForeignKey( author = models.ForeignKey(
User, User,
@ -25,32 +71,159 @@ class CaseStudy(models.Model):
editable=False editable=False
) )
project_name = models.CharField(max_length=128) # Date and time of submission
# Location of map pin date_created = models.DateTimeField(auto_now=True, null=False)
# Slug derived from entry_name, used in urls for SEO
slug = AutoSlugField(populate_from=['entry_name'])
# 1.1
entry_name = models.CharField(
verbose_name=_("Entry Name"),
help_text=_("Enter the name of the entry. This should usually be the\
name of project."),
max_length=128
)
# N/A - Not explicitly listed in spec
location = models.PointField() location = models.PointField()
supply_chain = models.CharField(
max_length=1, # 1.2
choices=SUPPLY_CHAIN_CHOICES sector_of_economy = models.CharField(
verbose_name=_("Sector of economy"),
help_text=_("Which sector of the renewable energy economy is most\
relevant?"),
max_length=3,
choices=SECTOR_CHOICES
) )
generation_type = models.CharField(
# 1.3
positive_or_negative = models.CharField(
verbose_name=_("Positive or negative?"),
help_text=_("Is the case study a positive case or a negative case?"),
max_length=1, max_length=1,
choices=GENERATION_TYPE_CHOICES choices=POSITIVE_NEGATIVE_CHOICES
) )
associated_companies = models.CharField(max_length=128)
financiers = models.CharField(max_length=128) # 1.4
important_lenders = models.CharField(max_length=128)
country = CountryField() country = CountryField()
affects_indigenous = models.BooleanField()
affects_indigenous_reason = models.TextField() # 1.5.1
proposed_start = models.DateField() area_of_land = models.IntegerField(
proposed_completion = models.DateField() verbose_name=_("Approximate land area"),
description = models.TextField() help_text=_("The area of land covered by the project (in km²)")
link_to_forum = models.URLField() )
image = models.ImageField()
references = models.TextField() # 1.5.2
commodities = models.CharField(max_length=128) land_ownership = models.CharField(
like_to_engage_developer = models.BooleanField() verbose_name=_("Land ownership"),
like_to_engage_investors = models.BooleanField() help_text=_("What type of ownership does the land fall under?"),
max_length=3,
choices=LAND_OWNERSHIP_CHOICES
)
# 1.5.3
land_ownership_details = models.CharField(
verbose_name=_("Land ownership details"),
help_text=_("Add any details and other remarks about the land\
ownership"),
max_length=256
)
# 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 = models.CharField(
verbose_name=_("Type of ecosystem"),
help_text=_("Select the most relevant type of ecosystem."),
max_length=6,
choices=TYPE_OF_ECOSYSTEM_CHOICES,
)
# 1.5.5.3
describe_ecosystem = models.CharField(
verbose_name=_("Describe the ecosystem"),
help_text=_("In your own words, add more detail about the ecosystem."),
max_length=256,
)
# 1.5.6
affects_indigenous = models.BooleanField(
verbose_name=_("Affects indigenous people?"),
help_text=_("Does the project affect indigenous people?")
)
# 1.5.6.1
affects_indigenous_detail = models.CharField(
verbose_name=_("Affects Indigenous - Details"),
help_text=_("What group of indigenous people does the community belong\
to?"),
max_length=256
)
# 1.6
project_status = models.CharField(
verbose_name=_("Status of Project"),
help_text=_("What is the status of the current project?"),
max_length=6,
choices=PROJECT_STATUS_CHOICES
)
# 1.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)"),
max_length=500
)
# 1.10
full_description = models.TextField(
verbose_name=_("Full Description"),
help_text=_("Describe the project in full. Separate paragraphs with a\
new line Please add as much detail as you feel is necessary\
here.")
)
# 1.15
image = models.ImageField(
verbose_name=_("Image")
)
# 1.16
video = models.URLField(
verbose_name=_("Video"),
max_length=43
)
# 1.18
community_voices = models.TextField(
verbose_name=_("Community Voices"),
help_text=_("Add any direct quotes from members of the community that\
relate to this project")
)
def __str__(self): def __str__(self):
return "%s in %s" % (self.project_name, self.country.name) """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)

4
apps/map/moderator.py Normal file
View File

@ -0,0 +1,4 @@
from moderation import moderation
from apps.map.models import CaseStudy
moderation.register(CaseStudy) # Uses default moderation settings

View File

@ -1,11 +0,0 @@
appdirs==1.4.3
Django==1.11.1
django-countries==4.5
django-crispy-forms==1.6.1
django-leaflet==0.22.0
gunicorn==19.7.1
packaging==16.8
psycopg2==2.7.1
pyparsing==2.2.0
pytz==2017.2
six==1.10.0

17274
apps/map/static/map/bundle.js Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,15 +0,0 @@
{% load staticfiles %}
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/"><img src="{% static "map/ojuso-logo-white.png" %}" alt="Ojuso Logo"></a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
{% block nav_links %}
{% endblock %}
</ul>
</div>
</div>
</nav>

View File

@ -1,11 +1,9 @@
{% extends "map/base.html" %} {% extends "base.html" %}
{% block stylesheets %} {% block stylesheets %}
{{ block.super }} {{ block.super }}
<style> <style>
body {
padding-top: 50px;
}
.page-lead { .page-lead {
padding: 40px 15px; padding: 40px 15px;
text-align: center; text-align: center;
@ -15,20 +13,15 @@
{% block body %} {% block body %}
{% include "map/_nav.html" %}
{% block nav_links %}
<li><a href="/case-studies">Case Studies</a></li>
{% endblock %}
<div class="container"> <div class="container">
<div class="page-lead"> <div class="page-lead">
<h1>{% block title %}{% endblock %}</h1> <h1 class="text-center">{% block title %}{% endblock %}</h1>
<p class="lead">{% block description %}{% endblock %}</p> <p class="lead text-center">{% block description %}{% endblock %}</p>
</div> </div>
{% block content %} {% block content %}
{% endblock %} {% endblock %}
</div><!-- /.container --> </div><!-- /.container -->
{% endblock %} {% endblock %}

View File

@ -1,13 +1,10 @@
{% extends "map/base.html" %} {% extends "base.html" %}
{% block stylesheets %} {% block stylesheets %}
{{ block.super }} {{ block.super }}
<style> <style>
body {
padding-top: 50px;
}
.jumbo { .jumbo {
height: calc(100% - 50px); height: calc(100% - 64px);
width: 100%; width: 100%;
position: absolute; position: absolute;
right: 0; right: 0;
@ -19,12 +16,10 @@
{% block body %} {% block body %}
{% include "map/_nav.html" %}
<div class="jumbo"> <div class="jumbo">
{% block content %} {% block content %}
{% endblock %} {% endblock %}
</div><!-- /.container --> </div><!-- /.container -->
{% endblock %} {% endblock %}

View File

@ -0,0 +1,117 @@
{% extends "base_with_jumbo.html" %}
{% load bootstrap3 %}
{% load compress %}
{% load i18n %}
{% load leaflet_tags %}
{% load humanize %}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<script src="bundle.js"></script>
</head>
{% block content %}
<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>
<div style="margin-top:70px;padding:0 20px;">
<h1>{{case_study.entry_name}}</h1>
<p>{{case_study.synopsis}}</p>
</div>
<div class="clearfix">
<div style="margin-left:20px;">
<span class="badge badge-pill bg-dark">{{case_study.get_sector_of_economy_display}}</span>
{% if case_study.positive_or_negative == "P" %}
<span class="badge badge-pill bg-success">{{case_study.get_positive_or_negative_display}}</span>
{% elif case_study.positive_or_negative == "N"%}
<span class="badge badge-pill bg-danger">{{case_study.get_positive_or_negative_display}}</span>
{% endif %}
<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>
<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&amp;showinfo=0" frameborder="0" allowfullscreen></iframe>
</div>
</div>
</div>
<div class="row" style="padding-top:30px;">
<div class="col-lg-8">
<div id="accordion" role="tablist">
<div class="card">
<div class="card-header" role="tab" id="headingOne">
<h5 class="mb-0">
<a data-toggle="collapse" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
{% trans "Full Description" %}
</a>
</h5>
</div>
<div id="collapseOne" class="collapse show" role="tabpanel" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body">
{{case_study.full_description}}
</div>
</div>
</div>
<div class="card">
<div class="card-header" role="tab" id="headingTwo">
<h5 class="mb-0">
<a class="collapsed" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
{% trans "Community Voices" %}
</a>
</h5>
</div>
<div id="collapseTwo" class="collapse" role="tabpanel" aria-labelledby="headingTwo" data-parent="#accordion">
<div class="card-body">
{{case_study.community_voices}}
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header">
{% trans "Factbar" %}
</div>
<div class="card-body">
<ul class="list-group list-group-flush">
{% if case_study.area_of_land %}
<li class="list-group-item">{% trans "Approximate land area"%}: {{case_study.area_of_land}} km²</li>
{% endif %}
</ul>
</div>
</div>
<div class="card">
<div class="card-header">
Attached Files
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<a href="#">File One</a></br>
<small class="text-muted">Uploaded one month ago</small>
</li>
<li class="list-group-item">
<a href="#">File Two</a></br>
<small class="text-muted">Uploaded 3 mins ago</small>
</li>
</ul>
</div>
</div>
</div>
</div>
<footer class="footer text-center">
<div class="container-fluid">
<span class="text-muted">Ojuso x Yansa</span>
</div>
</footer>
{% endblock %}
</html>

View File

@ -1,4 +1,4 @@
{% extends "map/base_with_container.html" %} {% extends "base_page.html" %}
{% load compress %} {% load compress %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load i18n %} {% load i18n %}
@ -21,4 +21,14 @@
{% block scripts %} {% block scripts %}
{% leaflet_js %} {% leaflet_js %}
<script type="text/javascript">
YourGeometryField = L.GeometryField.extend({
addTo: function (map) {
L.GeometryField.prototype.addTo.call(this, map);
// Customize map for field
console.log(this);
},
// See GeometryField source (static/leaflet/leaflet.forms.js) to override more stuff...
});
</script>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,47 @@
{% extends "base_page.html" %}
{% load bootstrap3 %}
{% load compress %}
{% load i18n %}
{% load humanize %}
{% block stylesheets %}
{{ block.super }}
<style>
a.btn-jumbo {
color: navy;
width:320px;
height:240px;
border: 1px solid black;
border-radius: 5px;
white-space: normal;
line-height:55px;
padding:80px 20px;
margin: 20px;
}
a.btn-jumbo > * {
vertical-align: middle;
display: inline-block;
line-height:20px;
}
div.btn-jumbo-group {
text-align: center;
}
</style>
{% endblock %}
{% block title %}{% trans "How much time do you have?" %}{% endblock %}
{% block description %}
{% trans "A complete picture is always more helpful but sometimes you don't have the time" %}
{% endblock %}
{% block content %}
<div class="btn-jumbo-group">
<a class="btn btn-jumbo bg-warning" href="{% url 'long-form' %}" role="button">
<h2>20+ Minutes</h2>
<p>Full Form (Preferred)</p>
</a>
<a class="btn btn-jumbo bg-success" href="{% url 'short-form' %}" role="button">
<h2>5-10 Minutes</h2>
<p>Express Form</p>
</a>
</div>
{% endblock %}

View File

@ -1,6 +1,5 @@
{% extends "map/base_with_jumbo.html" %} {% extends "base_with_jumbo.html" %}
{% load bootstrap3 %} {% load bootstrap3 %}
{% load compress %}
{% load i18n %} {% load i18n %}
{% load leaflet_tags %} {% load leaflet_tags %}
@ -46,9 +45,9 @@
onEachFeature: function (feature, layer) { onEachFeature: function (feature, layer) {
var modalname = "case-study-"+feature.id var modalname = "case-study-"+feature.id
layer.bindPopup( layer.bindPopup(
"<h3>"+feature.properties.project_name+"</h3>"+ "<p>"+feature.properties.entry_name+"</p>"+
"<button type='button' class='btn btn-primary btn-block' data-toggle='modal' data-target='#"+modalname+"'>" "<a class='btn btn-primary' href='case-study/"+feature.properties.slug+"' role='button'>"
+"{% trans "Quick View" %}"+"</button>" +"{% trans "View" %}"+"</a>"
); );
var modal = create( var modal = create(
"<div class='modal fade' id='"+modalname+"' tabindex='-1' role='dialog' aria-labelledby='"+modalname+"-label'>"+ "<div class='modal fade' id='"+modalname+"' tabindex='-1' role='dialog' aria-labelledby='"+modalname+"-label'>"+

View File

@ -5,9 +5,10 @@ from .models import CaseStudy
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.index, name='index'), url(r'^$', views.Map.as_view(), name='index'),
url(r'^data.geojson$', url(r'^data.geojson$', GeoJSONLayerView.as_view(model=CaseStudy, geometry_field='location'), name='data'),
GeoJSONLayerView.as_view(model=CaseStudy, geometry_field='location'), url(r'^case-study/create/?$', views.Create.as_view(), name="create"),
name='data'), url(r'^case-study/create/short/?$', views.ShortForm.as_view(), name='short-form'),
url(r'^case-study/add', views.form, name='form') url(r'^case-study/create/long/?$', views.LongForm.as_view(), name='long-form'),
url(r'^case-study/(?P<slug>[-\w]+)/?$', views.CaseStudyDetail.as_view(), name='detail')
] ]

View File

@ -1,12 +1,35 @@
from django.shortcuts import render from django.views.generic import DetailView
from django.views.generic.base import TemplateView
from .forms import CaseStudyForm from django.views.generic.edit import FormView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import CaseStudy
from .forms import ShortCaseStudyForm, LongCaseStudyForm
def index(request): class Map(TemplateView):
return render(request, 'map/index.html') template_name = "map/index.html"
def form(request): class Create(LoginRequiredMixin, TemplateView):
form = CaseStudyForm template_name = "map/how_much_time.html"
return render(request, 'map/form.html', {'form': form})
class BaseForm(LoginRequiredMixin, FormView):
"""This is the base class for the short and long forms. It handles any shared logic between the two subclasses."""
template_name = 'map/form.html'
class ShortForm(BaseForm):
"""Here, we use the short version of the form."""
form_class = ShortCaseStudyForm
class LongForm(BaseForm):
"""Here, we use the long version of the form."""
form_class = LongCaseStudyForm
class CaseStudyDetail(DetailView):
template_name = "map/detail.html"
model = CaseStudy
context_object_name = "case_study"

View File

3
apps/profiles/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

5
apps/profiles/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class ProfilesConfig(AppConfig):
name = 'profiles'

View File

3
apps/profiles/models.py Normal file
View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@ -0,0 +1,2 @@
{% extends "base_page.html" %}
Profile page

3
apps/profiles/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

7
apps/profiles/urls.py Normal file
View File

@ -0,0 +1,7 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.Profile.as_view(), name='profile'),
]

5
apps/profiles/views.py Normal file
View File

@ -0,0 +1,5 @@
from django.views.generic.base import TemplateView
class Profile(TemplateView):
template_name = "profiles/profile.html"

View File

@ -6,11 +6,13 @@ services:
- db:db - db:db
- cache:cache - cache:cache
volumes: volumes:
- ./apps:/app/apps
- ./ojusomap:/app/ojusomap
- /containers/map/static:/app/static - /containers/map/static:/app/static
- /containers/map/gunicorn.sock:/app/gunicorn.sock - /containers/map/gunicorn.sock:/app/gunicorn.sock
env_file: env_file:
- ./environment - ./local.env
command: /bin/sh -c "python3 manage.py migrate && python3 manage.py collectstatic --noinput && gunicorn --bind 0.0.0.0:8000 ojusomap.wsgi" command: /bin/sh -c "python3 manage.py migrate && DEBUG=1 python3 manage.py collectstatic --noinput && gunicorn --bind 0.0.0.0:8000 ojusomap.wsgi"
db: db:
image: mdillon/postgis:9.6-alpine image: mdillon/postgis:9.6-alpine

View File

@ -1,45 +1 @@
#!/bin/bash -e #!/bin/bash
export DEBUG=0
export ALLOWED_HOSTS=map.ojuso.org
export DATABASE_HOST=localhost
export DATABASE_NAME=postgres
export DATABASE_PASSWORD=2xXKKS9zdrBX9QJaV5Z5NPTiiW8LtTiR4vAGSACddqFTrBdhgwZHKYnLqjJedAi3
export EMAIL_HOST=mail.gandi.net
export EMAIL_HOST_USER=admin@ojuso.org
export EMAIL_HOST_PASSWORD=QN7yosrnch1le474H56mesVR1SRw6sfO3izJDZnJ6T62Cj9I57CplW6UYZY6VXsq7lLr868bIK3kSXGyWiSrAyWK
export EMAIL_PORT=587
export EMAIL_USE_TLS=1
export SECRET_KEY=a3DfjSmWkSffsPscRscqaxGv6HsBN8VKL8Q4EU4QcdEckB8scogrMP4tv7Eo7LZw
export SERVER_EMAIL=Ojuso\ Platform\ Notification\ \<admin@ojuso.org\>
export POSTGRES_USER=postgres
export POSTGRES_PASSWORD=2xXKKS9zdrBX9QJaV5Z5NPTiiW8LtTiR4vAGSACddqFTrBdhgwZHKYnLqjJedAi3
export DISCOURSE_DB_SOCKET=/var/run/postgresql
export DISCOURSE_DEVELOPER_EMAILS=admin@ojuso.org
export DISCOURSE_HOSTNAME=forum.ojuso.org
export DISCOURSE_SMTP_ADDRESS=mail.gandi.net
export DISCOURSE_SMTP_PASSWORD=QN7yosrnch1le474H56mesVR1SRw6sfO3izJDZnJ6T62Cj9I57CplW6UYZY6VXsq7lLr868bIK3kSXGyWiSrAyWK
export DISCOURSE_SMTP_PORT=587
export DISCOURSE_SMTP_USER_NAME=admin@ojuso.org
export DOCKER_HOST_IP=172.17.0.1
export LANG=en_US.UTF-8
export RAILS_ENV=production
export RUBY_GC_HEAP_GROWTH_MAX_SLOTS=40000
export RUBY_GC_HEAP_INIT_SLOTS=400000
export RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=1.5
export RUBY_GLOBAL_METHOD_CACHE_SIZE=131072
export UNICORN_SIDEKIQS=1
export UNICORN_WORKERS=4
export WEBLATE_DEBUG=0
export WEBLATE_LOGLEVEL=DEBUG
export WEBLATE_SITE_TITLE=Ojuso\ Weblate
export WEBLATE_ADMIN_NAME=Weblate\ Admin
export WEBLATE_ADMIN_EMAIL=admin@ojuso.org
export WEBLATE_ADMIN_PASSWORD=zPFPtHLsRRFAAcApeGd23aV6Hg66KpTkWs2becsMMoL9dTeKLNt3PfH5Bzhyna8q
export WEBLATE_SERVER_EMAIL=noreply@ojuso.org
export WEBLATE_DEFAULT_FROM_EMAIL=noreply@ojuso.org
export WEBLATE_ALLOWED_HOSTS=*
export WEBLATE_REGISTRATION_OPEN=1
export WEBLATE_GITHUB_USERNAME=livmackintosh
export WEBLATE_EMAIL_HOST=mail.gandi.net
export WEBLATE_EMAIL_USER=admin@ojuso.org
export WEBLATE_EMAIL_PASSWORD=QN7yosrnch1le474H56mesVR1SRw6sfO3izJDZnJ6T62Cj9I57CplW6UYZY6VXsq7lLr868bIK3kSXGyWiSrAyWK

17
local.env Normal file
View File

@ -0,0 +1,17 @@
# Django Configuration
DEBUG=1
ALLOWED_HOSTS=localhost
DATABASE_HOST=db
DATABASE_NAME=postgres
DATABASE_PASSWORD=postgres
EMAIL_HOST=mail
EMAIL_HOST_USER=admin@ojuso.org
EMAIL_HOST_PASSWORD=
EMAIL_PORT=1025
EMAIL_USE_TLS=0
SECRET_KEY=kZQPK56roVhFkwPqFF9xZoHFlw38uVuXNCjtXor6FRiieiYds9ltuM6oZeZ75CEe
SERVER_EMAIL=Ojuso Platform Notification <livvy@base.nu>
# Postgres Database Setup
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres

41
local.yml Normal file
View File

@ -0,0 +1,41 @@
version: "3"
services:
map:
build: .
links:
- db:db
- cache:cache
- mailhog:mail
volumes:
- .containers/map/static:/app/static
- .containers/map/gunicorn.sock:/app/gunicorn.sock
- ./apps:/app/apps
- ./ojusomap:/app/ojusomap
- ./support:/app/support
ports:
- 8000:8000
env_file:
- ./local.env
command: /bin/sh -c "python3 manage.py collectstatic --noinput ; python3 manage.py runserver 0.0.0.0:8000"
db:
image: mdillon/postgis:9.6-alpine
volumes:
- .containers/db:/var/lib/postgresql/data
- ./support/postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
ports:
- "127.0.0.1:5432:5432"
env_file:
- ./local.env
mailhog:
image: mailhog/mailhog
ports:
- 1025:1025
- 8025:8025
cache:
image: memcached:1.4
volumes:
weblate-data:

View File

@ -35,12 +35,18 @@ ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost').split()
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'apps.contact',
'apps.map', 'apps.map',
'apps.profiles',
'django.contrib.admin', 'django.contrib.admin',
'registration',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'django.contrib.humanize',
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages', 'django.contrib.messages',
'whitenoise.runserver_nostatic',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django.contrib.gis', 'django.contrib.gis',
'bootstrap3', 'bootstrap3',
@ -48,13 +54,16 @@ INSTALLED_APPS = [
'compressor', 'compressor',
'crispy_forms', 'crispy_forms',
'django_extensions', 'django_extensions',
'envelope',
'leaflet', 'leaflet',
'moderation',
'rest_framework', 'rest_framework',
'rest_framework_gis', 'rest_framework_gis',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
@ -66,10 +75,12 @@ MIDDLEWARE = [
ROOT_URLCONF = 'ojusomap.urls' ROOT_URLCONF = 'ojusomap.urls'
SITE_ID = 1
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [], 'DIRS': [os.path.join(BASE_DIR, 'ojusomap/templates/')],
'APP_DIRS': True, 'APP_DIRS': True,
'OPTIONS': { 'OPTIONS': {
'context_processors': [ 'context_processors': [
@ -95,7 +106,6 @@ EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER')
EMAIL_PORT = os.getenv('EMAIL_PORT', 25) EMAIL_PORT = os.getenv('EMAIL_PORT', 25)
EMAIL_USE_TLS = bool(int(os.getenv('EMAIL_USE_TLS', False))) EMAIL_USE_TLS = bool(int(os.getenv('EMAIL_USE_TLS', False)))
EMAIL_SUBJECT_PREFIX = "Ojuso Platform" EMAIL_SUBJECT_PREFIX = "Ojuso Platform"
SERVER_EMAIL = os.getenv('SERVER_EMAIL', 'root@localhost') SERVER_EMAIL = os.getenv('SERVER_EMAIL', 'root@localhost')
@ -131,6 +141,8 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
# Registration (Redux)
ACCOUNT_ACTIVATION_DAYS = 3
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/ # https://docs.djangoproject.com/en/1.11/topics/i18n/
@ -163,10 +175,9 @@ STATIC_URL = os.getenv("STATIC_URL", '/static/')
STATICFILES_FINDERS = [ STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'compressor.finders.CompressorFinder',
] ]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Cache # Cache
# https://docs.djangoproject.com/en/1.11/topics/cache/ # https://docs.djangoproject.com/en/1.11/topics/cache/
@ -204,7 +215,7 @@ REST_FRAMEWORK = {
# Django Crispy Forms # Django Crispy Forms
# http://django-crispy-forms.readthedocs.io/en/latest/ # http://django-crispy-forms.readthedocs.io/en/latest/
CRISPY_TEMPLATE_PACK = 'bootstrap3' CRISPY_TEMPLATE_PACK = 'bootstrap4'
# Django-Leaflet # Django-Leaflet
# https://django-leaflet.readthedocs.io/en/latest/ # https://django-leaflet.readthedocs.io/en/latest/

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,9 @@
{% extends 'base_page.html' %}
{% block title %}
Shucks.
{% endblock %}
{% block description %}
Looks like you're not supposed to be here.
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends 'base_page.html' %}
{% block title %}
Shucks.
{% endblock %}
{% block description %}
You've taken a wrong turn and we can't find the page you're looking for.
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends 'base_page.html' %}
{% block title %}
Shucks.
{% endblock %}
{% block description %}
An unknown server error occurred. Sorry about that.
{% endblock %}

View File

@ -0,0 +1,66 @@
{% spaceless %}
{% load i18n %}
{% load leaflet_tags %}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<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>
{# Additional Stylesheets #}
{% block stylesheets %}
<style>
.navbar-brand {padding: 5px 15px;}
.navbar-brand > img {height: 40px;}
</style>
{% endblock %}
</head>
<body>
<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"/>
</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>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">Map <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Policy</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">FAQ</a>
</li>
</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>
{% block body %}{% endblock %}
</body>
{# CDN Javascript #}
<script src="//code.jquery.com/jquery-3.2.1.min.js"
integrity="sha384-xBuQ/xzmlsLoJpyjoggmTEz8OWUFM0/RC5BsqQBDX2v5cMvDHcMakNTNrHIW2I5f"
crossorigin="anonymous">
</script>
{% block scripts %}{% endblock %}
</html>
{% endspaceless %}

View File

@ -0,0 +1,27 @@
{% extends "base.html" %}
{% block stylesheets %}
{{ block.super }}
<style>
.page-lead {
padding: 40px 15px;
text-align: center;
}
</style>
{% endblock %}
{% block body %}
<div class="container">
<div class="page-lead">
<h1 class="text-center">{% block title %}{% endblock %}</h1>
<p class="lead text-center">{% block description %}{% endblock %}</p>
</div>
{% block content %}
{% endblock %}
</div><!-- /.container -->
{% endblock %}

View File

@ -0,0 +1,25 @@
{% extends "base.html" %}
{% block stylesheets %}
{{ block.super }}
<style>
.jumbo {
height: calc(100% - 64px);
width: 100%;
position: absolute;
right: 0;
bottom: 0;
left: 0;
}
</style>
{% endblock %}
{% block body %}
<div class="jumbo">
{% block content %}
{% endblock %}
</div><!-- /.container -->
{% endblock %}

View File

@ -0,0 +1 @@
{% extends 'base_page.html' %}

View File

@ -0,0 +1 @@
{% extends 'base_page.html' %}

View File

@ -0,0 +1,10 @@
{% 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
</div>
{% endblock %}

View File

@ -0,0 +1 @@
Activate your Ojuso Identity account.

View File

@ -0,0 +1,24 @@
{% extends "base_page.html" %}
{% load bootstrap3 %}
{% load crispy_forms_tags %}
{% load envelope_tags %}
{% load i18n %}
{% block page_title %}{% trans "Login"%} | Ojuso{% endblock %}
{% block content %}
<div class="container" style="max-width:520px;">
<div class="page-lead">
<h2>Login</h2>
<p class="lead">{% trans "Welcome!" %}</p>
</div>
{% bootstrap_messages %}
<form action="{% url 'auth_login' %}" method="post">
{% csrf_token %}
{% antispam_fields %}
{{form|crispy}}
<p><a href="{% url 'auth_password_reset' %}">{% trans "Lost password?" %}</a></p>
<input class="btn btn-success pull-right" type="submit" name="submit" value="{% trans 'Login' %}"/>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends "base_page.html" %}
{% load bootstrap3 %}
{% load crispy_forms_tags %}
{% load envelope_tags %}
{% load i18n %}
{% block page_name %}Registration{% endblock %}
{% block content %}
<p class="text-center">{% trans "You've just been logged out." %} <a href="{% url 'auth_login' %}">{% trans "Click here to login again." %}</p>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'auth_password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}

View File

@ -0,0 +1,12 @@
{% extends "base_page.html" %}
{% load bootstrap3 %}
{% block page_name %}Registration{% endblock %}
{% block content %}
<div class="container">
<div class="page-lead">
<h2>Registration</h2>
<p class="lead">Account registration is currently closed. Come back soon!</p>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,22 @@
{% extends "base_page.html" %}
{% load bootstrap3 %}
{% load crispy_forms_tags %}
{% load envelope_tags %}
{% 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>
</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"/>
</form>
</div>
{% endblock %}

View File

@ -14,6 +14,7 @@ Including another URLconf
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
""" """
from django.conf.urls import include, url from django.conf.urls import include, url
from django.urls import reverse
from django.conf.urls.i18n import i18n_patterns from django.conf.urls.i18n import i18n_patterns
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -51,8 +52,12 @@ urlpatterns = [
url(r'api/', include(apirouter.urls)), url(r'api/', include(apirouter.urls)),
url(r'^admin/', admin.site.urls), url(r'^admin/', admin.site.urls),
url(r'^cas/', include('cas_server.urls', namespace='cas_server')), url(r'^cas/', include('cas_server.urls', namespace='cas_server')),
# url(r'^contact/', include('apps.contact.urls'), name="contact")
] ]
urlpatterns += i18n_patterns( urlpatterns += i18n_patterns(
url(r'^accounts/profile/', include('apps.profiles.urls')),
# 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"), url(r'', include('apps.map.urls'), name="map"),
) )

View File

@ -1,14 +1,20 @@
appdirs==1.4.3 appdirs==1.4.3
Django==1.10.7 brotlipy==0.7.0
Django==1.11.6
django-appconf==1.0.2 django-appconf==1.0.2
django-bootstrap3==8.2.3 django-bootstrap3==8.2.3
django-braces==1.11.0
django-cas-server==0.8.0 django-cas-server==0.8.0
django-compressor==2.1.1 django-compressor==2.1.1
django-countries==4.5 django-countries==4.5
django-crispy-forms==1.6.1 django-crispy-forms==1.6.1
django-envelope==1.3
django-extensions==1.7.9 django-extensions==1.7.9
django-geojson==2.10.0 django-geojson==2.10.0
django-leaflet==0.22.0 #django-leaflet==0.22.0
-e git://github.com/makinacorpus/django-leaflet.git@a43acc5fed6674b413a6fab0feeb7c44e67c2ca8#egg=django-leaflet
django-moderation==0.5.0
django-registration-redux==1.6
djangorestframework==3.6.3 djangorestframework==3.6.3
djangorestframework-gis==0.11.2 djangorestframework-gis==0.11.2
gunicorn==19.7.1 gunicorn==19.7.1
@ -25,3 +31,4 @@ requests==2.14.2
requests-futures==0.9.7 requests-futures==0.9.7
rjsmin==1.0.12 rjsmin==1.0.12
six==1.10.0 six==1.10.0
whitenoise==3.3.1