Skip to content

Commit 403e184

Browse files
committed
First check in of Django/Python API settings and basic We Vote architecture framework.
1 parent adf2ef6 commit 403e184

34 files changed

+1408
-1
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ node_modules/
143143
/geo/data/
144144
/**/migrations/*.py
145145
!/**/migrations/__init__.py
146-
wevoteserver/environment_variables.json
146+
config/environment_variables.json
147147

148148
# Heroku Related #
149149
##################

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 We Vote USA
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Procfile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: gunicorn config.wsgi:application --log-file -

config/__init__.py

Whitespace-only changes.

config/base.py

+302
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
# config/base.py (Settings Base, inherited by local.py)
2+
# Brought to you by We Vote. Be good.
3+
# -*- coding: UTF-8 -*-
4+
5+
import json
6+
##import logging
7+
import os
8+
from django.core.exceptions import ImproperlyConfigured
9+
# Consider switching to the way that Two Scoops of Django 1.8 suggests file path handling, section 5.6
10+
# from unipath import Path
11+
12+
13+
# SECURITY WARNING: don't run with debug turned on in production!
14+
# Override in local.py for development
15+
DEBUG = False
16+
17+
# Load JSON-based environment_variables if available
18+
json_environment_variables = {}
19+
##try:
20+
with open("config/environment_variables.json") as f:
21+
json_environment_variables = json.loads(f.read())
22+
##except StandardError as e:
23+
## print "base.py: environment_variables.json missing" # Can't use logger in the settings file due to loading sequence
24+
25+
26+
def get_environment_variable(var_name, json_environment_vars=json_environment_variables):
27+
"""
28+
Get the environment variable or return exception.
29+
From Two Scoops of Django 1.8, section 5.3.4
30+
"""
31+
try:
32+
return json_environment_vars[var_name] # Loaded from array above
33+
except KeyError:
34+
# variable wasn't found in the JSON environment variables file, so now look in the server environment variables
35+
print "base.py: failed to load {} from JSON file".format(var_name) # Can't use logger in the settings file
36+
37+
try:
38+
# Environment variables can be set with this for example: export GOOGLE_CIVIC_API_KEY=<API KEY HERE>
39+
return os.environ[var_name]
40+
except KeyError:
41+
# Can't use logger in the settings file due to loading sequence
42+
error_msg = "Unable to set the {} variable from os.environ or JSON file".format(var_name)
43+
raise ImproperlyConfigured(error_msg)
44+
45+
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
46+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
47+
PROJECT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
48+
# Consider switching to the way that Two Scoops of Django 1.8 suggests file path handling, section 5.6
49+
50+
# SECURITY WARNING: keep the secret key used in production secret!
51+
SECRET_KEY = get_environment_variable("SECRET_KEY")
52+
53+
# Comment out when running Heroku
54+
ALLOWED_HOSTS = []
55+
56+
57+
# Application definition
58+
59+
INSTALLED_APPS = (
60+
'django.contrib.admin',
61+
'django.contrib.auth',
62+
'django.contrib.contenttypes',
63+
'django.contrib.sessions',
64+
'django.contrib.messages',
65+
'django.contrib.staticfiles',
66+
67+
# third party
68+
'bootstrap3',
69+
'social.apps.django_app.default',
70+
# 'crispy_forms',
71+
72+
# project specific
73+
# 'election_office_measure',
74+
# 'exception',
75+
# 'follow',
76+
# 'import_export',
77+
# 'import_export_azavea_cicero',
78+
# 'import_export_google_civic',
79+
# 'import_export_maplight',
80+
# 'import_export_theunitedstatesio',
81+
# 'import_export_twitter',
82+
# 'import_export_voting_info_project',
83+
# 'organization',
84+
# 'politician',
85+
# 'position',
86+
# 'region_jurisdiction',
87+
# 'rest_framework',
88+
# 'support_oppose_deciding',
89+
# 'tag',
90+
# 'twitter',
91+
# 'utils',
92+
# 'ux_birch',
93+
# 'ux_oak', # The business logic for this particular version of We Vote
94+
'wevote_functions',
95+
# 'wevote_settings',
96+
# 'wevote_social',
97+
'voter', # See also AUTH_USER_MODEL in config/settings.py
98+
)
99+
100+
MIDDLEWARE_CLASSES = (
101+
'django.contrib.sessions.middleware.SessionMiddleware',
102+
'django.middleware.common.CommonMiddleware',
103+
'django.middleware.csrf.CsrfViewMiddleware',
104+
'django.contrib.auth.middleware.AuthenticationMiddleware',
105+
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
106+
'django.contrib.messages.middleware.MessageMiddleware',
107+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
108+
'django.middleware.security.SecurityMiddleware',
109+
# 'wevote_social.middleware.SocialMiddleware',
110+
)
111+
112+
AUTHENTICATION_BACKENDS = (
113+
# 'social.backends.facebook.FacebookOAuth2',
114+
# 'social.backends.twitter.TwitterOAuth',
115+
'django.contrib.auth.backends.ModelBackend',
116+
)
117+
118+
ROOT_URLCONF = 'config.urls'
119+
120+
TEMPLATES = [
121+
{
122+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
123+
'DIRS': [os.path.join(BASE_DIR, 'templates')],
124+
'APP_DIRS': True,
125+
'OPTIONS': {
126+
'context_processors': [
127+
'django.template.context_processors.debug',
128+
'django.template.context_processors.request',
129+
'django.contrib.auth.context_processors.auth',
130+
'django.contrib.messages.context_processors.messages',
131+
'django.template.context_processors.media', # Django Cookbook
132+
'django.template.context_processors.static', # Django Cookbook
133+
# 'social.apps.django_app.context_processors.backends',
134+
# 'social.apps.django_app.context_processors.login_redirect',
135+
# 'wevote_social.context_processors.profile_photo',
136+
],
137+
},
138+
},
139+
]
140+
141+
WSGI_APPLICATION = 'config.wsgi.application'
142+
143+
# Internationalization
144+
# https://docs.djangoproject.com/en/1.8/topics/i18n/
145+
146+
LANGUAGE_CODE = 'en-us'
147+
148+
TIME_ZONE = 'UTC'
149+
150+
USE_I18N = True
151+
152+
USE_L10N = True
153+
154+
USE_TZ = True
155+
156+
# Described here: https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#a-full-example
157+
AUTH_USER_MODEL = 'voter.Voter'
158+
159+
# Static files (CSS, JavaScript, Images)
160+
# https://docs.djangoproject.com/en/1.8/howto/static-files/
161+
STATIC_URL = '/static/'
162+
STATIC_ROOT = os.path.join(PROJECT_PATH, "static", "static") # Django Cookbook
163+
MEDIA_URL = '/media/' # Django Cookbook
164+
MEDIA_ROOT = os.path.join(PROJECT_PATH, "static", "media") # Django Cookbook
165+
166+
# We want to default to cookie storage of messages so we don't overload our app servers with session data
167+
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
168+
169+
# Default settings described here: http://django-bootstrap3.readthedocs.org/en/latest/settings.html
170+
BOOTSTRAP3 = {
171+
172+
# The URL to the jQuery JavaScript file
173+
'jquery_url': '//code.jquery.com/jquery.min.js',
174+
175+
# The Bootstrap base URL
176+
'base_url': '//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/',
177+
178+
# The complete URL to the Bootstrap CSS file (None means derive it from base_url)
179+
'css_url': None,
180+
181+
# The complete URL to the Bootstrap CSS file (None means no theme)
182+
'theme_url': None,
183+
184+
# The complete URL to the Bootstrap JavaScript file (None means derive it from base_url)
185+
'javascript_url': None,
186+
187+
# Put JavaScript in the HEAD section of the HTML document (only relevant if you use bootstrap3.html)
188+
'javascript_in_head': False,
189+
190+
# Include jQuery with Bootstrap JavaScript (affects django-bootstrap3 template tags)
191+
'include_jquery': False,
192+
193+
# Label class to use in horizontal forms
194+
'horizontal_label_class': 'col-md-3',
195+
196+
# Field class to use in horizontal forms
197+
'horizontal_field_class': 'col-md-9',
198+
199+
# Set HTML required attribute on required fields
200+
'set_required': True,
201+
202+
# Set HTML disabled attribute on disabled fields
203+
'set_disabled': False,
204+
205+
# Set placeholder attributes to label if no placeholder is provided
206+
'set_placeholder': True,
207+
208+
# Class to indicate required (better to set this in your Django form)
209+
'required_css_class': '',
210+
211+
# Class to indicate error (better to set this in your Django form)
212+
'error_css_class': 'has-error',
213+
214+
# Class to indicate success, meaning the field has valid input (better to set this in your Django form)
215+
'success_css_class': 'has-success',
216+
217+
# Renderers (only set these if you have studied the source and understand the inner workings)
218+
'formset_renderers': {
219+
'default': 'bootstrap3.renderers.FormsetRenderer',
220+
},
221+
'form_renderers': {
222+
'default': 'bootstrap3.renderers.FormRenderer',
223+
},
224+
'field_renderers': {
225+
'default': 'bootstrap3.renderers.FieldRenderer',
226+
'inline': 'bootstrap3.renderers.InlineFieldRenderer',
227+
},
228+
}
229+
230+
LOGIN_REDIRECT_URL = '/'
231+
SOCIAL_AUTH_FACEBOOK_KEY = get_environment_variable("SOCIAL_AUTH_FACEBOOK_KEY")
232+
SOCIAL_AUTH_FACEBOOK_SECRET = get_environment_variable("SOCIAL_AUTH_FACEBOOK_SECRET")
233+
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', 'user_friends']
234+
SOCIAL_AUTH_TWITTER_KEY = get_environment_variable("SOCIAL_AUTH_TWITTER_KEY")
235+
SOCIAL_AUTH_TWITTER_SECRET = get_environment_variable("SOCIAL_AUTH_TWITTER_SECRET")
236+
SOCIAL_AUTH_PIPELINE = (
237+
'social.pipeline.social_auth.social_details',
238+
'social.pipeline.social_auth.social_uid',
239+
'social.pipeline.social_auth.auth_allowed',
240+
'social.pipeline.social_auth.social_user',
241+
'social.pipeline.user.get_username',
242+
'social.pipeline.social_auth.associate_by_email',
243+
'social.pipeline.user.create_user',
244+
'social.pipeline.social_auth.associate_user',
245+
'social.pipeline.social_auth.load_extra_data',
246+
'social.pipeline.user.user_details'
247+
)
248+
249+
250+
# ########## Logging configurations ###########
251+
# LOG_STREAM Boolean True will turn on stream handler and write to command line.
252+
# LOG_FILE String Path to file to write to. Make sure executing
253+
# user has permissions.
254+
# LOG_STREAM_LEVEL Integer Log level of stream handler: CRITICAL, ERROR, INFO, WARN, DEBUG
255+
# LOG_FILE_LEVEL Integer Log level of file handler: CRITICAL, ERROR, INFO, WARN, DEBUG
256+
# NOTE: These should be set in the environment_variables.json file
257+
def convert_logging_level(log_level_text_descriptor):
258+
import logging
259+
# Assume error checking has been done and that the string is a valid logging level
260+
if log_level_text_descriptor == "CRITICAL":
261+
return logging.CRITICAL
262+
if log_level_text_descriptor == "ERROR":
263+
return logging.ERROR
264+
if log_level_text_descriptor == "INFO":
265+
return logging.INFO
266+
if log_level_text_descriptor == "WARN":
267+
return logging.WARN
268+
if log_level_text_descriptor == "DEBUG":
269+
return logging.DEBUG
270+
271+
272+
def lookup_logging_level(log_level_text_descriptor, log_level_default="ERROR"):
273+
import logging
274+
available_logging_levels = ["CRITICAL", "ERROR", "INFO", "WARN", "DEBUG"]
275+
276+
if log_level_text_descriptor.upper() in available_logging_levels:
277+
# print "log_level_text_descriptor: {}".format(log_level_text_descriptor)
278+
return convert_logging_level(log_level_text_descriptor)
279+
else:
280+
# The log_level_text_descriptor is not a valid level, so use the debug level
281+
if log_level_default.upper() in available_logging_levels:
282+
# print "log_level_default: {}".format(log_level_default)
283+
return convert_logging_level(log_level_default)
284+
else:
285+
# print "log_level failure default: {}".format("ERROR")
286+
return logging.ERROR
287+
288+
289+
# Which level of logging event should get written to the command line?
290+
LOG_STREAM = get_environment_variable('LOG_STREAM') # Turn command line logging on or off
291+
# print "Current LOG_STREAM_LEVEL setting:"
292+
LOG_STREAM_LEVEL = lookup_logging_level(get_environment_variable("LOG_STREAM_LEVEL"), "DEBUG")
293+
# Which level of logging event should get written to the log file?
294+
LOG_FILE = get_environment_variable('LOG_FILE') # Location of the log file
295+
LOG_FILE_LEVEL = lookup_logging_level(get_environment_variable("LOG_FILE_LEVEL"), "ERROR")
296+
# print "Current LOG_FILE_LEVEL setting:"
297+
298+
# Using conventions from django.contrib:
299+
# https://docs.djangoproject.com/en/1.8/ref/contrib/gis/geoip/#geoip-settings
300+
GEOIP_PATH=os.path.join(BASE_DIR, 'geo', 'data')
301+
GEOIP_COUNTRY='GeoIP.dat'
302+
GEOIP_CITY='GeoLiteCity.dat'
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"_comment": "local.py settings, including database",
3+
"DATABASE_ENGINE": "django.db.backends.postgresql_psycopg2",
4+
"DATABASE_NAME": "WeVoteDB",
5+
"DATABASE_USER": "postgres",
6+
"DATABASE_PASSWORD": "",
7+
"DATABASE_HOST": "",
8+
"DATABASE_PORT": "",
9+
10+
"_comment": "These are the levels of logging available: CRITICAL, ERROR, INFO, WARN, DEBUG",
11+
"_comment": "*** LOG_STREAM turns on or off the messages to the command line: true or false",
12+
"LOG_STREAM": true,
13+
"_comment": "*** LOG_STREAM_LEVEL is the level of logging printed to the command line",
14+
"LOG_STREAM_LEVEL": "DEBUG",
15+
"_comment": "*** LOG_FILE is the location on the disk of the log file",
16+
"LOG_FILE": "/var/log/wevote/wevoteserver.log",
17+
"_comment": "*** LOG_FILE_LEVEL is the level of logging written to the log file",
18+
"LOG_FILE_LEVEL": "ERROR",
19+
20+
"_comment": "import_export",
21+
"WE_VOTE_API_KEY": "",
22+
"ORGANIZATIONS_URL": "http://my.wevoteusa.org/import_export/organizations/?format=json",
23+
"ORGANIZATIONS_JSON_FILE": "import_export/import_data/organizations_sample.json",
24+
"CANDIDATE_CAMPAIGNS_URL": "http://my.wevoteusa.org/import_export/candidate_campaigns/?format=json",
25+
"CANDIDATE_CAMPAIGNS_JSON_FILE": "import_export/import_data/candidate_campaigns_sample.json",
26+
"POSITIONS_URL": "http://my.wevoteusa.org/import_export/positions/?format=json",
27+
"POSITIONS_JSON_FILE": "import_export/import_data/positions_sample.json",
28+
29+
"_comment": "import_export_google_civic",
30+
"GOOGLE_CIVIC_API_KEY": "",
31+
"VOTER_INFO_URL": "https://www.googleapis.com/civicinfo/v2/voterinfo",
32+
"VOTER_INFO_JSON_FILE": "import_export_google_civic/import_data/voterinfo_sample.json",
33+
34+
"_comment": "import_export_theunitedstatesio",
35+
"LEGISLATORS_CURRENT_CSV_FILE": "import_export_theunitedstatesio/import_data/legislators-current.csv",
36+
37+
"_comment": "import_export_voting_info_project",
38+
"VOTING_INFO_PROJECT_SAMPLE_XML_FILE": "import_export_voting_info_project/import_data/sample_feed.xml",
39+
40+
"SOCIAL_AUTH_FACEBOOK_KEY": "",
41+
"SOCIAL_AUTH_FACEBOOK_SECRET": "",
42+
"SOCIAL_AUTH_TWITTER_KEY": "",
43+
"SOCIAL_AUTH_TWITTER_SECRET": "",
44+
"SECRET_KEY": "(-ack%@p)$dpr-4*q$a@ir%64(_(q6!ve@=r&5i*@-fw6bjnqq",
45+
46+
"_comment": "End of json_environment_variables.json"
47+
}

0 commit comments

Comments
 (0)