Source code for settings

"""Provides system-level settings and access to environment variables.
All variables corresponding to environment variables have documentation for ReadTheDocs."""

import os
import sys
import dj_database_url
import djcelery

###############
# PATH settings
###############
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))

ROOT_URLCONF = 'urls'

FIXTURE_DIRS = [
    os.path.join(PROJECT_ROOT, "fixtures"),
    ]

# directories which hold static files
STATICFILES_DIRS = (
    os.path.join(PROJECT_ROOT, 'static'),
    )

# URL that handles the static files such as css, img, and js
STATIC_URL = "/site_media/static/"

# Absolute path to the directory that holds static files.
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'site_media', 'static')

# prefix for all uploaded media files
MAKAHIKI_MEDIA_PREFIX = "media"

#######################
# Template settings
#######################
TEMPLATE_DIRS = (
    os.path.join(os.path.dirname(__file__), "templates"),
    os.path.join(PROJECT_ROOT, "apps"),
    )

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
    )

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request",
    "django.core.context_processors.static",
    'django.contrib.messages.context_processors.messages',
    "apps.managers.challenge_mgr.context_processors.competition",
    )

######################
# MIDDLEWARE settings
######################
MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    #always start with this for caching

    'django.middleware.gzip.GZipMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.transaction.TransactionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.doc.XViewMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',

    # comment out only for debug_toolbar
    #'debug_toolbar.middleware.DebugToolbarMiddleware',

    'apps.lib.django_cas.middleware.CASMiddleware',
    'apps.managers.player_mgr.middleware.LoginMiddleware',
    'apps.managers.log_mgr.middleware.LoggingMiddleware',

    'django.middleware.cache.FetchFromCacheMiddleware',
    #always end with this for caching
    )

# comment out only for debug_toolbar
#INTERNAL_IPS = ('127.0.0.1',)

######################
# AUTH settings
######################
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'apps.managers.auth_mgr.cas_backend.MakahikiCASBackend',
    )

###################
# Authentication
###################
LOGIN_URL = "/landing/"
LOGIN_REDIRECT_URLNAME = "home_index"
LOGIN_REDIRECT_URL = "/home"
RESTRICTED_URL = '/restricted/'

#################
# CACHE settings
#################
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
CACHE_MIDDLEWARE_SECONDS = 600

#########################
# INSTALLED_APPS settings
#########################
INSTALLED_APPS = (
    # Makahiki pages
    'apps.pages',

    # Makahiki components
    'apps.managers.auth_mgr',
    'apps.managers.challenge_mgr',
    'apps.managers.team_mgr',
    'apps.managers.resource_mgr',
    'apps.managers.player_mgr',
    'apps.managers.predicate_mgr',
    'apps.managers.score_mgr',
    'apps.managers.smartgrid_mgr',
    'apps.managers.cache_mgr',
    'apps.managers.log_mgr',

    # 3rd party libraries
    'apps.lib.django_cas',
    'apps.lib.facebook_api',
    'apps.lib.avatar',

    # Django apps
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.humanize',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    #'django.contrib.admindocs',
    'markup_deprecated',

    # external
    'django_extensions',
    'gunicorn',
    'storages',
    'kombu.transport.django',
    'djcelery',
    #'django-taggit',

    # comment out only for debug_toolbar
    #'debug_toolbar',
)

################################
# INSTALLED DEFAULT Widgets for all pages
################################
INSTALLED_DEFAULT_WIDGET_APPS = (
    'notifications',
    'ask_admin',
    'quests',
)
for widget in INSTALLED_DEFAULT_WIDGET_APPS:
    INSTALLED_APPS += ("apps.widgets." + widget, )

##########################
# INSTALLED common Widgets
##########################
INSTALLED_COMMON_WIDGET_APPS = (
    'help',
    'resource_goal',
    'resource_scoreboard',
    'wallpost',
    'status',
)
for widget in INSTALLED_COMMON_WIDGET_APPS:
    INSTALLED_APPS += ("apps.widgets." + widget, )

################################
# INSTALLED Widgets
################################
INSTALLED_WIDGET_APPS = (
    'action_feedback',
    'ask_admin',
    'badge_scoreboard',
    'badges',
    'bonus_points',
    'home',
#     'education',
    'energy_power_meter',
    'my_achievements',
    'my_commitments',
    'my_info',
    'popular_tasks',
    'prizes',
    'quests',
    'raffle',
    'scoreboard',
    'participation',
    'smartgrid',
    'smartgrid_design',
    'smartgrid_library',
    'smartgrid_play_tester',
    'team_members',
    'upcoming_events',
    'logging',
    'help.intro',
    'help.faq',
    'help.rule',
    'resource_goal.energy',
    'resource_goal.water',
    'resource_scoreboard.energy',
    'resource_scoreboard.water',
    'wallpost.user_wallpost',
    'wallpost.system_wallpost',
    'status.prizes',
    'status.rsvps',
    'status.users',
    'status.actions',
    'status.referrals',
    'status.wattdepot',
    'status.twitter',
    'status.badges',
    'status.DEGG',
    'status.DWGG',
    'unlock_creator',
)

for widget in INSTALLED_WIDGET_APPS:
    INSTALLED_APPS += ("apps.widgets." + widget, )

# migration support, need to be the last app.
# nose has to be after south!
INSTALLED_APPS += ('south', 'django_nose',)

##########################################################
# INSTALLED Themes. Please keep them in alphabetical order
##########################################################
INSTALLED_THEMES = (
    'theme-bubbles',
    'theme-bumblebee',
    'theme-forest',
    'theme-google',
    'theme-hpu',
    'theme-revolusun',
    'theme-sonora',
    'theme-space',
    'theme-wave',
)


################
# TEST settings
################
# South
SOUTH_TESTS_MIGRATE = False

# Use Nose as the test runner.
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'


##############################
# LOGGING settings
##############################
LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %'
                      '(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
        },
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'django.utils.log.NullHandler',
            },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            },
    },
    'loggers': {
        'django': {
            'handlers': ['null'],
            'propagate': True,
            'level': 'INFO',
            },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
            },
    }
}

#########################
# MISC
#########################

# Permissions for large uploaded files.
FILE_UPLOAD_PERMISSIONS = 0644

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# Locale Info
TIME_ZONE = 'Pacific/Honolulu'
LOCALE_SETTING = 'en'
LANGUAGE_CODE = 'en_US.UTF-8'

# Markdown info
MARKDOWN_LINK = "http://daringfireball.net/projects/markdown/syntax"
MARKDOWN_TEXT = "Uses <a href=\"" + MARKDOWN_LINK + "\" target=\"_blank\">Markdown</a> formatting."

# Makahiki Predicates documentation
PREDICATE_DOC_LINK = "http://makahiki.readthedocs.org/en/latest/predicates.html"
PREDICATE_DOC_TEXT = "Uses <a href=\"" + PREDICATE_DOC_LINK + "\" target=\"_blank\">"\
                     "Makahiki Predicates</a>."

SERIALIZATION_MODULES = {
    'csv': 'snippetscream.csv_serializer',
    }


##############################
# Dummy settings for CHALLENGE
##############################
# Create a dummy challenge object and variables so that IDEs are OK.
# This object will be instantiated for real from the DB ChallengeSetting object.
class Challenge():
    "Encapsulates settings for the challenge."
    name = None

CHALLENGE = Challenge()

##########
# Celery
##########
BROKER_URL = "django://"  # tell kombu to use the Django database as the message queue

djcelery.setup_loader()

CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'

##################################################################################################
# Load environment variables
# Note: All environment variables have a corresponding Python variable for documentation purposes.
##################################################################################################

# Helper lambda for retrieving environment variables:
env = lambda e, d: os.environ[e] if e in os.environ else d

# DB settings
MAKAHIKI_USE_HEROKU = env('MAKAHIKI_USE_HEROKU', '').lower() == "true"
"""[Optional] If "true", use Heroku hosting, Otherwise, use local hosting."""

MAKAHIKI_DATABASE_URL = env('MAKAHIKI_DATABASE_URL', '')
"""[Required if MAKAHIKI_USE_HEROKU is not true] Specify the Database URL.
Example: postgres://username:password@db_host:db_port/db_name"""

if MAKAHIKI_USE_HEROKU:
    DATABASE_URL = env('DATABASE_URL', '')
    DATABASES = {'default': dj_database_url.parse(DATABASE_URL)}
    DATABASES['default']['ATOMIC_REQUESTS'] = True
else:
    if MAKAHIKI_DATABASE_URL:
        DATABASES = {'default': dj_database_url.parse(MAKAHIKI_DATABASE_URL)}
        DATABASES['default']['ATOMIC_REQUESTS'] = True
    else:
        if 'READTHEDOCS' not in os.environ:
            print "Environment variable MAKAHIKI_DATABASE_URL not defined. Exiting."
            sys.exit(1)

# Admin info Settings
MAKAHIKI_ADMIN_INFO = env('MAKAHIKI_ADMIN_INFO', '')
"""[Required]  Specify the makahiki admin account and password.
Example:  admin:changeme"""
if MAKAHIKI_ADMIN_INFO:
    admin_info = MAKAHIKI_ADMIN_INFO.split(":")
    ADMIN_USER = admin_info[0]
    ADMIN_PASSWORD = admin_info[1]
else:
    if 'READTHEDOCS' not in os.environ:
        print "Environment variable MAKAHIKI_ADMIN_INFO not defined. Exiting."
        sys.exit(1)

# email Settings
MAKAHIKI_EMAIL_INFO = env('MAKAHIKI_EMAIL_INFO', '')
"""[Required if enabling email]  Specify the email host user and password.
Example:  kukuicup@gmail.com:changeme"""
if MAKAHIKI_EMAIL_INFO:
    email_info = MAKAHIKI_EMAIL_INFO.split(":")
    EMAIL_HOST_USER = email_info[0]
    EMAIL_HOST_PASSWORD = email_info[1]

# DEBUG settings
MAKAHIKI_DEBUG = env('MAKAHIKI_DEBUG', '').lower() == "true"
"""[Optional]  If "true", enable debug mode, with better error messages.
Otherwise use production mode."""
DEBUG = MAKAHIKI_DEBUG
TEMPLATE_DEBUG = MAKAHIKI_DEBUG

# CACHE settings
MAKAHIKI_USE_MEMCACHED = env('MAKAHIKI_USE_MEMCACHED', '').lower() == "true"
"""[Optional] If "true", use memcache. Otherwise no caching is used."""
if MAKAHIKI_USE_MEMCACHED:
    if os.environ.get('MEMCACHIER_SERVERS', ''):
        os.environ['MEMCACHE_SERVERS'] = os.environ.get('MEMCACHIER_SERVERS', '')
        os.environ['MEMCACHE_USERNAME'] = os.environ.get('MEMCACHIER_USERNAME', '')
        os.environ['MEMCACHE_PASSWORD'] = os.environ.get('MEMCACHIER_PASSWORD', '')

        CACHES = {
            'default': {
                'BACKEND': 'django_pylibmc.memcached.PyLibMCCache',
                'LOCATION': os.environ.get('MEMCACHIER_SERVERS', ''),
                'TIMEOUT': 500,
                'BINARY': True,
                }
        }
    else:
        CACHES = {'default':
                    {'BACKEND': 'django_pylibmc.memcached.PyLibMCCache',
                     'LOCATION': '127.0.0.1',
                     'BINARY': True,
                     }
                  }
else:
    CACHES = {'default':
                {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}}

# static media settings
MAKAHIKI_USE_S3 = env('MAKAHIKI_USE_S3', '').lower() == "true"
"""[Optional] If "true", use the Amazon S3 storage facility. Otherwise use local folder."""

MAKAHIKI_AWS_ACCESS_KEY_ID = env('MAKAHIKI_AWS_ACCESS_KEY_ID', '')
"""[Required if MAKAHIKI_USE_S3 is true]  The Amazon access key ID."""
MAKAHIKI_AWS_SECRET_ACCESS_KEY = env('MAKAHIKI_AWS_SECRET_ACCESS_KEY', '')
"""[Required if MAKAHIKI_USE_S3 is true]  The Amazon secret access key."""
MAKAHIKI_AWS_STORAGE_BUCKET_NAME = env('MAKAHIKI_AWS_STORAGE_BUCKET_NAME', '')
"""[Required if MAKAHIKI_USE_S3 is true]  The Amazon storage bucket name."""

if MAKAHIKI_USE_S3:
    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
    #STATICFILES_STORAGE = DEFAULT_FILE_STORAGE
    AWS_ACCESS_KEY_ID = MAKAHIKI_AWS_ACCESS_KEY_ID
    AWS_SECRET_ACCESS_KEY = MAKAHIKI_AWS_SECRET_ACCESS_KEY
    AWS_STORAGE_BUCKET_NAME = MAKAHIKI_AWS_STORAGE_BUCKET_NAME
    AWS_QUERYSTRING_AUTH = False

    MEDIA_URL = 'https://s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME
    STATIC_URL = MEDIA_URL + 'static/'
    SERVE_MEDIA = False
else:
    # URL that handles the media files such as uploads.
    MEDIA_URL = "/site_media/"
    # Absolute path to the directory that holds media.
    MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'site_media')
    # serve media through django.views.static.serve.
    SERVE_MEDIA = True

# settings to use less files
MAKAHIKI_USE_LESS = env('MAKAHIKI_USE_LESS', '').lower() == "true"
"""[Optional] If "true", use LESS files to style pages. Otherwise use the latest version of CSS."""

# LDAP settings
MAKAHIKI_LDAP_BIND_DN = env('MAKAHIKI_LDAP_BIND_DN', '')
"""[Required for LDAP services] Provide the Bind DN."""
AUTH_LDAP_BIND_DN = MAKAHIKI_LDAP_BIND_DN

MAKAHIKI_LDAP_BIND_PASSWORD = env('MAKAHIKI_LDAP_BIND_PWD', '')
"""[Required for LDAP services] Provide the Bind password."""
AUTH_LDAP_BIND_PASSWORD = MAKAHIKI_LDAP_BIND_PASSWORD

MAKAHIKI_LDAP_USE_CN = env('MAKAHIKI_LDAP_USE_CN', '').lower() == "true"
"""[Optional] If "true", use the LDAP cn attribute as the username, otherwise use uid attribute."""

if AUTH_LDAP_BIND_DN and AUTH_LDAP_BIND_PASSWORD:
    AUTHENTICATION_BACKENDS += (
        'apps.managers.auth_mgr.ldap_backend.MakahikiLDAPBackend',
        )

MAKAHIKI_SECRET_KEY = env('MAKAHIKI_SECRET_KEY',
                          'yvzg-s=^gb#)e6l7jq_$%ft=i7jln&izs2@4+3!5%#unumorn-')
"""[Optional] Specifies the Django secret key setting.
See https://docs.djangoproject.com/en/dev/ref/settings/#secret-key"""
SECRET_KEY = MAKAHIKI_SECRET_KEY

MAKAHIKI_USE_FACEBOOK = env('MAKAHIKI_USE_FACEBOOK', '').lower() == "true"
"""[Optional] If "true", use facebook integration."""
MAKAHIKI_FACEBOOK_APP_ID = env('MAKAHIKI_FACEBOOK_APP_ID', '')
"""[Required if using Facebook] App ID required for Facebook integration."""
MAKAHIKI_FACEBOOK_SECRET_KEY = env('MAKAHIKI_FACEBOOK_SECRET_KEY', '')
"""[Required if using Facebook] Secret key required for Facebook integration."""
if MAKAHIKI_USE_FACEBOOK:
    if not MAKAHIKI_FACEBOOK_APP_ID:
        print "Environment variable MAKAHIKI_FACEBOOK_APP_ID not defined. Exiting."
        sys.exit(1)
    if not MAKAHIKI_FACEBOOK_SECRET_KEY:
        print "Environment variable MAKAHIKI_FACEBOOK_SECRET_KEY not defined. Exiting."
        sys.exit(1)

MAKAHIKI_USE_LOGFILE = env('MAKAHIKI_USE_LOGFILE', '').lower() == "true"
"""[Optional] if "true", use logfile to store application logs."""
if MAKAHIKI_USE_LOGFILE:
    # Default log file location.
    LOG_FILE = 'makahiki.log'
    LOGGING['loggers']['makahiki_logger'] = {
        'handlers': ['file'],
        'level': 'INFO',
        }
    LOGGING['handlers']['file'] = {
        'level': 'INFO',
        'class': 'logging.FileHandler',
        'filename': LOG_FILE,
        'formatter': 'simple',
        }

MAKAHIKI_USE_WATTDEPOT3 = env('MAKAHIKI_USE_WATTDEPOT3', '').lower() == "true"
"""[Required if using wattdepot3] wattdepot admin name."""
WATTDEPOT_ADMIN_NAME = env('WATTDEPOT_ADMIN_NAME', '')
"""[Required if using wattdepot3] wattdepot admin password."""
WATTDEPOT_ADMIN_PASSWORD = env('WATTDEPOT_ADMIN_PASSWORD', '')

# Allow the IPv4 address 192.169.56.4 for Vagrant testing
# Variable is set in Vagrant's makahiki_env.sh
MACHINE_IS_VAGRANT = env('MACHINE_IS_VAGRANT', '').lower() == "true"
if MACHINE_IS_VAGRANT:
    ALLOWED_HOSTS = ['192.168.56.4']
# Set allowed host domains for normal operation.
else:
    ALLOWED_HOSTS = ['localhost', '127.0.0.1',
                     'kukuicup.manoa.hawaii.edu', 'demo.kukuicup.org',
                     '.herokuapp.com', '.heroku.com']