diff --git a/.dockerignore b/.dockerignore
index 2a717da57..b0631b58d 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,6 +1,8 @@
# Version Control
.git
+**settings_local.py
+
# Python
*.pyc
*.pyo
diff --git a/.env.sample b/.env.sample
deleted file mode 100644
index a3f7a5bb4..000000000
--- a/.env.sample
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Required
-#
-
-# From which directory to pull project-specific resources
-# Examples:
-CUSTOM_ASSET_DIR=core-cms
-CUSTOM_ASSET_DIR=frontera-cms
-CUSTOM_ASSET_DIR=protx-cms
diff --git a/.gitignore b/.gitignore
index 391987d8b..e59994e06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,8 @@ repo_name.var
settings.json
taccsite_cms/secrets.py
*.custom.yml
+*settings_custom*.py
+*settings_local*.py
# Makefile var
cms_name.var
diff --git a/Dockerfile b/Dockerfile
index 13bc3f8db..2cbe9c057 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -25,4 +25,4 @@ WORKDIR /code
RUN pip3 install --no-cache-dir -r requirements.txt
# build assets
-RUN npm ci && npm run settings && npm run build
+RUN npm ci && npm run build
diff --git a/README.md b/README.md
index 899bcc0ca..114e8d606 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ The TACC CORE-CMS can be run using Docker and Docker Compose, both locally and i
CUSTOM_ASSET_DIR=example-cms
```
- \* Where `example-cms` is the project to be run. _See [(Optional) Custom Resources per CMS Project](#optional-custom-resources-per-cms-project). Refer to `.env.sample` for other settings._
+ \* Where `example-cms` is the project to be run. _See [(Optional) Custom Resources per CMS Project](#optional-custom-resources-per-cms-project)._
1. Initialize / Update submodules.
1. `git submodule init`\
_(Adds `cms-site-resources` repo as submodule at `taccsite_custom/`. Only necessary once per `CORE-cms` repo clone.)_
diff --git a/conf/css/.postcssrc.yml b/conf/css/.postcssrc.yml
index 4dd78259b..7938a3ed5 100644
--- a/conf/css/.postcssrc.yml
+++ b/conf/css/.postcssrc.yml
@@ -13,6 +13,7 @@ plugins:
postcss-preset-env:
# SEE: https://github.com/csstools/postcss-preset-env#features
stage: false
+ # SEE: https://github.com/csstools/postcss-preset-env/blob/master/src/lib/plugins-by-id.js#L35
features:
custom-media-queries: true
media-query-ranges: true
diff --git a/package.json b/package.json
index b5e56c1a8..3439077e8 100644
--- a/package.json
+++ b/package.json
@@ -4,10 +4,10 @@
"license": "MIT",
"description": "The core CMS codebase for all new and updated TACC CMS sites.",
"scripts": {
+ "prebuild": "python3 taccsite_cms/settings_to_json.py",
"build": "npm run build:css",
- "build:css": "npm run settings && node postcss.js",
- "watch": "npm-watch",
- "settings": "python3 taccsite_cms/settings_to_json.py"
+ "build:css": "node postcss.js",
+ "watch": "npm-watch"
},
"// scripts": {
"prebuild": "Export Django settings to JSON (for Node to use)",
diff --git a/taccsite_cms/contrib/bootstrap4_djangocms_link/cms_plugins.py b/taccsite_cms/contrib/bootstrap4_djangocms_link/cms_plugins.py
index 8fc6a7db2..6b287e6a8 100644
--- a/taccsite_cms/contrib/bootstrap4_djangocms_link/cms_plugins.py
+++ b/taccsite_cms/contrib/bootstrap4_djangocms_link/cms_plugins.py
@@ -6,7 +6,7 @@
# SEE: https://github.com/django-cms/djangocms-bootstrap4/pull/138
import copy
- from django.utils.translation import gettext_lazy as _
+ from django.utils.translation import gettext as _
from cms.plugin_pool import plugin_pool
diff --git a/taccsite_cms/contrib/bootstrap4_djangocms_picture/cms_plugins.py b/taccsite_cms/contrib/bootstrap4_djangocms_picture/cms_plugins.py
index 5f7bf7f42..262d4e623 100644
--- a/taccsite_cms/contrib/bootstrap4_djangocms_picture/cms_plugins.py
+++ b/taccsite_cms/contrib/bootstrap4_djangocms_picture/cms_plugins.py
@@ -2,7 +2,7 @@
# FAQ: Bootstrap Image plugin has features not desirable in TACC plugins
# FAQ: We must not break sites that already use Bootstrap Image plugin
try:
- from django.utils.translation import gettext_lazy as _
+ from django.utils.translation import gettext as _
from cms.plugin_pool import plugin_pool
diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py
index fece7a03f..82a7db1c9 100644
--- a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py
+++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py
@@ -1,6 +1,6 @@
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import gettext as _
from taccsite_cms.contrib.constants import TEXT_FOR_NESTED_PLUGIN_CONTENT_SWAP
from taccsite_cms.contrib.helpers import concat_classnames
diff --git a/taccsite_cms/contrib/taccsite_data_list/models.py b/taccsite_cms/contrib/taccsite_data_list/models.py
index 750698739..431e874e8 100644
--- a/taccsite_cms/contrib/taccsite_data_list/models.py
+++ b/taccsite_cms/contrib/taccsite_data_list/models.py
@@ -1,7 +1,7 @@
from cms.models.pluginmodel import CMSPlugin
from django.db import models
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import gettext as _
from djangocms_attributes_field import fields
diff --git a/taccsite_cms/contrib/taccsite_sample/cms_plugins.py b/taccsite_cms/contrib/taccsite_sample/cms_plugins.py
index f56b1d5a9..86b4d1e08 100644
--- a/taccsite_cms/contrib/taccsite_sample/cms_plugins.py
+++ b/taccsite_cms/contrib/taccsite_sample/cms_plugins.py
@@ -1,7 +1,7 @@
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from cms.models.pluginmodel import CMSPlugin
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import gettext as _
from django.utils.encoding import force_text
from .models import TaccsiteSample
diff --git a/taccsite_cms/contrib/taccsite_system_monitor/cms_plugins.py b/taccsite_cms/contrib/taccsite_system_monitor/cms_plugins.py
index 2202609fa..d85811068 100644
--- a/taccsite_cms/contrib/taccsite_system_monitor/cms_plugins.py
+++ b/taccsite_cms/contrib/taccsite_system_monitor/cms_plugins.py
@@ -1,6 +1,6 @@
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import gettext as _
from taccsite_cms.contrib.helpers import concat_classnames
diff --git a/taccsite_cms/contrib/taccsite_system_monitor/models.py b/taccsite_cms/contrib/taccsite_system_monitor/models.py
index 91dbae3d6..6820012d6 100644
--- a/taccsite_cms/contrib/taccsite_system_monitor/models.py
+++ b/taccsite_cms/contrib/taccsite_system_monitor/models.py
@@ -1,5 +1,5 @@
from cms.models.pluginmodel import CMSPlugin
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import gettext as _
from django.db import models
diff --git a/taccsite_cms/default_secrets.py b/taccsite_cms/default_secrets.py
deleted file mode 100644
index 6e2a1158c..000000000
--- a/taccsite_cms/default_secrets.py
+++ /dev/null
@@ -1,316 +0,0 @@
-# TACC CMS SITE TEMPLATE SETTINGS.
-# DEFAULT VALUES.
-# CHANGE BEFOR DEV/PREPROD/PRODUCTION DEPLOYMENT.
-
-########################
-# DJANGO SETTINGS
-########################
-
-_SECRET_KEY = 'replacethiswithareallysecureandcomplexsecretkeystring'
-_DEBUG = True # False for Prod.
-_CONSOLE_LOG_ENABLED = False # Boolean check to turn on/off console logging statements.
-
-# Specify allowed hosts or use an asterisk to allow any host and simplify the config.
-# _ALLOWED_HOSTS = ['hostname.tacc.utexas.edu', 'host.ip.v4.address', '0.0.0.0', 'localhost', '127.0.0.1'] # In production.
-_ALLOWED_HOSTS = ['0.0.0.0', '127.0.0.1', 'localhost', '*'] # In development.
-
-# Boolean check to see if ldap is being used by the site.
-# Requires django-auth-ldap ≥ 2.0.0
-_LDAP_ENABLED = False
-
-# Boolean check to determine the appropriate database settings when using containers.
-_USING_CONTAINERS = True
-
-########################
-# DATABASE SETTINGS
-########################
-
-if _USING_CONTAINERS:
- # used in container deployments.
- _DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql_psycopg2',
- 'PORT': '5432',
- 'NAME': 'taccsite',
- 'USER': 'postgresadmin',
- 'PASSWORD': 'taccforever', # Change before live deployment.
- 'HOST': 'core_cms_postgres'
- }
- }
-else:
- # used in local dev, venv or manual deployments.
- _DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql_psycopg2',
- 'PORT': '5432',
- 'NAME': 'taccsite',
- 'USER': 'postgresadmin',
- 'PASSWORD': 'taccforever', # Change before live deployment.
- 'HOST': 'localhost'
- }
- }
-
-########################
-# DJANGO CMS SETTINGS
-########################
-
-# CMS Site (allows for multiple sites on a single CMS)
-_SITE_ID = 1
-_CMS_TEMPLATES = (
- # Customize this list in per-project `secrets.py`
- # FAQ: First template is default template
- # REF: http://docs.django-cms.org/en/latest/how_to/install.html#templates
-
- # For standard pages (has Container and Breadcrumbs)
- ('standard.html', 'Standard'),
- # For content that spans full window width (no Container nor Breadcrumbs)
- ('fullwidth.html', 'Full Width'),
-
- # Any project that needs per-project styles must have a custom template
- # FAQ: This is a tedious solution until a cleaner solution is devised
- # TODO: Automate per-project asset load and update exisitng sites as needed
- # ('name-of-project/templates/fullwidth.html', 'Fullwidth (Custom)'),
- # NOTE: If project later uses custom template, then for that project:
- # 1. Rename standard default template to "DEPRECATED […]".
- # 2. Update all pages to use the custom default template.
- # 3. Disable standard default template (remove from `_CMS_TEMPLATES`).
- # ('fullwidth.html', 'DEPRECATED Fullwidth'),
-
- # Any portal whose homepage has NO design must enable and use this template
- # ('home_portal.html', 'Standard Portal Homepage'),
-
- # All portals should enable all of these templates
- # FAQ: If this becomes mandatory, then in `settings.py`:
- # `if _PORTAL: [ manually add these entries ]`
- # ('guide.html', 'Guide'),
- # ('guides/getting_started.html', 'Guide: Getting Started'),
- # ('guides/data_transfer.html', 'Guide: Data Transfer'),
- # ('guides/data_transfer.globus.html', 'Guide: Globus Data Transfer'),
- # ('guides/portal_technology.html', 'Guide: Portal Technology Stack'),
-
- # For now, only Core portal should enable this template
- # FAQ: We know not yet how to auto-replicate pages and plugins across sites
- # ('style_guide.html', 'Style Guide'),
-)
-
-########################
-# GOOGLE ANALYTICS
-########################
-
-# To use during dev, Tracking Protection in browser needs to be turned OFF.
-_GOOGLE_ANALYTICS_PROPERTY_ID = "UA-123ABC@%$&-#"
-_GOOGLE_ANALYTICS_PRELOAD = True
-
-########################
-# CMS FORMS
-########################
-
-# Create CMS Forms
-# SEE: https://pypi.org/project/djangocms-forms/
-# SEE: https://www.google.com/recaptcha/admin/create
-_DJANGOCMS_FORMS_RECAPTCHA_PUBLIC_KEY = ""
-_DJANGOCMS_FORMS_RECAPTCHA_SECRET_KEY = ""
-
-########################
-# ELASTICSEARCH
-########################
-
-_ES_AUTH = 'username:password'
-_ES_HOSTS = 'http://elasticsearch:9200'
-_ES_INDEX_PREFIX = 'cms-dev-{}'
-_ES_DOMAIN = 'http://localhost:8000'
-
-########################
-# FEATURES
-########################
-
-"""
-Features for the CMS that can be turned either ON or OFF
-
-Usage:
-
-- For baked-in features, like BRANDING or PORTAL, see relevant section instead.
-- For optional features, look below, and enable feature(s) via _FEATURES list.
-
-Baked-In Feature Setting Example.
-
-# Desctipion of feature X
-# SEE: [link to user/div guide about feature]
-_FEATURE_A = "someValue"
-
-Optional Feature Toggle Example.
-
-_FEATURES = {
- # Desctipion of feature X
- # SEE: [link to user/dev guide about feature]
- "X": True,
-
- # Desctipion of feature Y
- # SEE: [link to user/dev guide about feature]
- "Y": False,
-
- # Desctipion of feature Z
- # SEE: [link to user/dev guide about feature]
- "Z": True,
-}
-
-"""
-
-_FEATURES = {
- # Blog/News & Social Media Metadata
- # GL-42: Split this into two features
- # SEE: https://confluence.tacc.utexas.edu/x/EwDeCg
- # SEE: https://confluence.tacc.utexas.edu/x/FAA9Cw
- "blog": False,
-}
-
-########################
-# BRANDING & LOGOS & FAVICON
-########################
-# TODO: GH-59: Use Dict Not Array for Branding Settings
-
-# Visual theme for the CMS
-
-"""
-Optional theming of CMS (certain themes may only affect some elements)
-Usage:
-- None (standard theme)
-- 'has-dark-logo'
-"""
-
-_THEME = None
-
-# Branding settings for portal and navigation.
-
-"""
-Additional Branding and Portal Logos for Partner & Affiliate Organizations
-
-Usage:
-
-- For each beand used in the templating, add corresponding new settings values to this file (see example below).
-- New branding settings must be added to the _BRANDING list to render in the template.
-- The order of the _BRANDING list determines the rendering order of the elements in the template.
-- The portal logo setting must be assigned to the _LOGO variable to render in the template.
-- The following VALUES for new elements set in the configuration object must exist in the portal css as well:
- - Any new selectors or css styles (add to /taccsite_cms/static/site_cms/css/src/_imports/branding_logos.css)
- - Image files being references (add to /taccsite_cms/static/site_cms/img/org_logos)
-
-Values to populate (for an array):
-
-_SETTING_NAME = [ # The name of the branding or logo config setting object.
- "org_name", # The name of the organization the branding belongs too.
- "img_file_src", # Path and filename relative to the static files folder.
- "img_element_classes", # The list of selectors to apply to the rendered element, these need to exist in the css/scss.
- "a_target_url", # The href link to follow when clicked, use "/" for portal logos.
- "a_target_type", # The target to open the new link in, use _blank for external links, _self for internal links.
- "alt_text", # The text to read or render for web assistance standards.
- "cors_setting", # The CORS setting for the image, set to anonymous by default.
- "visibility" # Toggles wether or not to display the element in the template, use True to render, False to hide.
-]
-
-Values to populate (for a dict):
-
-_SETTING_NAME = { # The name of the favicon config setting object.
- "img_file_src": "…", # Path and filename relative to the static files folder.
-}
-
-Branding Configuration Example.
-
-_ANORG_BRANDING = [
- "anorg",
- "site_cms/img/org_logos/anorg-logo.png"
- "branding-anorg",
- "https://www.anorg.com/"
- "_blank",
- "ANORG Logo",
- "anonymous",
- "True"
-]
-
-Logo Configuration Example.
-
-_ANORG_LOGO = [
- "anorg",
- "site_cms/img/org_logos/anorg-logo.png"
- "branding-anorg",
- "/"
- "_self",
- "ANORG Logo",
- "anonymous",
- "True"
-]
-
-Favicon Configuration Example.
-
-_ANORG_FAVICON = {
- "img_file_src": "site_cms/img/favicons/favicon.ico"
-}
-"""
-
-########################
-# BRANDING
-
-_TACC_BRANDING = [
- "tacc",
- "site_cms/img/org_logos/tacc-white.png",
- "branding-tacc", # Unused but kept to retain index count # GH-59: Remove
- "https://www.tacc.utexas.edu/",
- "_blank",
- "TACC Logo",
- "anonymous",
- "True"
-]
-
-_UTEXAS_BRANDING = [
- "utexas",
- "site_cms/img/org_logos/utaustin-white.png",
- "branding-utaustin", # Unused but kept to retain index count # GH-59: Remove
- "https://www.utexas.edu/",
- "_blank",
- "University of Texas at Austin Logo",
- "anonymous",
- "True"
-]
-
-_NSF_BRANDING = [
- "nsf",
- "site_cms/img/org_logos/nsf-white.png",
- "branding-nsf", # Unused but kept to retain index count # GH-59: Remove
- "https://www.nsf.gov/",
- "_blank",
- "NSF Logo",
- "anonymous",
- "True"
-]
-
-_BRANDING = [ _TACC_BRANDING, _UTEXAS_BRANDING ] # Default TACC Portal.
-# _BRANDING = [ _NSF_BRANDING, _TACC_BRANDING, _UTEXAS_BRANDING ] # NSF Funded TACC Portal.
-
-########################
-# LOGOS
-
-_PORTAL_LOGO = [
- "portal",
- "site_cms/img/org_logos/portal.png",
- "", # Unused, but kept to retain index count
- "/",
- "_self",
- "Portal Logo",
- "anonymous",
- "True"
-]
-
-_LOGO = _PORTAL_LOGO # Default Portal Logo.
-
-########################
-# FAVICON
-
-_FAVICON = {
- "img_file_src": "site_cms/img/favicons/favicon.ico"
-}
-
-########################
-# PORTAL
-########################
-
-_PORTAL = False # True for any CMS that is part of a Portal.
diff --git a/taccsite_cms/remote_cms_auth.py b/taccsite_cms/remote_cms_auth.py
new file mode 100644
index 000000000..4e767d795
--- /dev/null
+++ b/taccsite_cms/remote_cms_auth.py
@@ -0,0 +1,96 @@
+import inspect
+from django.http import HttpResponse, HttpResponseRedirect
+from django.contrib.auth.backends import ModelBackend
+from django.contrib.auth import get_user_model
+from django.contrib import auth as auth
+import requests
+import logging
+from django.conf import settings
+
+UserModel = get_user_model()
+
+logger = logging.getLogger(__name__)
+
+
+def verify_and_auth(request):
+ user = auth.authenticate(request)
+ if user:
+ # User is valid. Set request.user and persist user in the session by logging the user in.
+ request.user = user
+ auth.login(request, user)
+ response = HttpResponseRedirect(request.GET.get('next', \
+ getattr(settings, 'LOGIN_REDIRECT_URL', '/workbench/dashboard/')))
+ else:
+ response = HttpResponseRedirect('/')
+ return response
+
+
+class CorePortalAuthBackend(ModelBackend):
+ """
+ Validates core portal session
+ Extends Django ModelBackend, parts of this were taken from Django's source:
+ https://github.com/django/django/blob/stable/2.2.x/django/contrib/auth/backends.py#L128
+ """
+ create_unknown_user = True
+
+ def authenticate(self, request):
+ response = requests.get('{0}/api/users/auth/'.format( \
+ getattr(settings, 'CEP_AUTH_VERIFICATION_ENDPOINT', 'http://django:6000')),
+ cookies={'coresessionid': request.COOKIES.get('coresessionid')})
+ user_data = response.json()
+ if user_data is None or user_data['username'] is None:
+ return None
+ username = user_data['username']
+ email = user_data['email']
+ first_name = user_data['first_name']
+ last_name = user_data['last_name']
+
+ if request.user.is_authenticated:
+ self._remove_invalid_user(request)
+
+ if self.create_unknown_user:
+ user, created = UserModel._default_manager.get_or_create(**{
+ UserModel.USERNAME_FIELD: username
+ })
+ user.email = email
+ user.first_name = first_name
+ user.last_name = last_name
+ user.save()
+ if created:
+ args = (request, user)
+ try:
+ inspect.getcallargs(self.configure_user, request, user)
+ except TypeError:
+ args = (user,)
+ warnings.warn(
+ 'Update %s.configure_user() to accept `request` as '
+ 'the first argument.'
+ % self.__class__.__name__, RemovedInDjango31Warning
+ )
+ user = self.configure_user(*args)
+ else:
+ try:
+ user = UserModel._default_manager.get_by_natural_key(username)
+ except UserModel.DoesNotExist:
+ pass
+ return user if self.user_can_authenticate(user) else None
+
+ def _remove_invalid_user(self, request):
+ """
+ Remove the current authenticated user
+ """
+ try:
+ stored_backend = load_backend(request.session.get(auth.BACKEND_SESSION_KEY, ''))
+ except ImportError:
+ # backend failed to load
+ auth.logout(request)
+ else:
+ if isinstance(stored_backend, RemoteUserBackend):
+ auth.logout(request)
+
+ def configure_user(self, request, user):
+ """
+ Configure a user after creation and return the updated user.
+ By default, return the user unmodified.
+ """
+ return user
diff --git a/taccsite_cms/settings.py b/taccsite_cms/settings.py
index c81b555b9..d20c41a7e 100644
--- a/taccsite_cms/settings.py
+++ b/taccsite_cms/settings.py
@@ -1,13 +1,9 @@
-# taccsite_cms/settings.py
"""
-Django settings for taccsite_cms project.
-
+Django settings
Generated by 'django-admin startproject' using Django 1.11.22.
-
For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/
-
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/
"""
@@ -15,91 +11,171 @@
import logging
import os
from glob import glob
+import ldap
+from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
-
+SECRET_KEY = 'CHANGE_ME'
def gettext(s): return s
+DATA_DIR = os.path.dirname(os.path.dirname(__file__))
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-# Import secret values dynamically without breaking portal.
-def getsecrets():
- new_secrets = {}; # Var to hold secret values once imported succesfully.
- # Check for production secrets.
- try:
- print('Checking for secret production values')
- import taccsite_cms.secrets as secrets # Prod/Staging/Local Dev values (used instead of the default values if present)
- new_secrets = secrets
- print('Production secrets found, using values')
- except ModuleNotFoundError as err:
- # Error handling
- print(err)
- print('No production secrets found')
- pass
- # Check for the default secret values.
- try:
- print('Checking for default secret values')
- import taccsite_cms.default_secrets as default_secrets # Default demo values (works for basic local dev out of the box)
- new_secrets = default_secrets
- print('Default secrets found, using default values')
- except ModuleNotFoundError as err:
- # Error handling
- print(err)
- print('No default secrets found')
- print('Check that you have a secrets.py or default_secrets.py')
- finally:
- # Return the secret values if they are found.
- return new_secrets
-
-# Assign secret settings values.
-current_secrets = getsecrets()
-
-# Boolean check to turn on/off console logging statements.
-CONSOLE_LOG_ENABLED = current_secrets._CONSOLE_LOG_ENABLED
-
-# Verifying console logging is on.
-if CONSOLE_LOG_ENABLED:
- print("--> Variable CONSOLE_LOG_ENABLED: ", CONSOLE_LOG_ENABLED)
-
-LDAP_ENABLED = current_secrets._LDAP_ENABLED
-
-if CONSOLE_LOG_ENABLED:
- print("--> Variable LDAP_ENABLED: ", LDAP_ENABLED)
-
-if LDAP_ENABLED:
- import ldap
- from django_auth_ldap.config \
- import LDAPSearch, GroupOfNamesType
+DEBUG = True # False for Prod.
-DATA_DIR = os.path.dirname(os.path.dirname(__file__))
+# Specify allowed hosts or use an asterisk to allow any host and simplify the config.
+# ALLOWED_HOSTS = ['hostname.tacc.utexas.edu', 'host.ip.v4.address', '0.0.0.0', 'localhost', '127.0.0.1'] # In production.
+ALLOWED_HOSTS = ['0.0.0.0', '127.0.0.1', 'localhost', '*'] # In development.
-if CONSOLE_LOG_ENABLED:
- print("--> Variable DATA_DIR: ", DATA_DIR)
+# Requires django-auth-ldap ≥ 2.0.0
+LDAP_ENABLED = True
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+########################
+# DATABASE SETTINGS
+########################
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2',
+ 'PORT': '5432',
+ 'NAME': 'taccsite',
+ 'USER': 'postgresadmin',
+ 'PASSWORD': 'taccforever', # Change before live deployment.
+ 'HOST': 'core_cms_postgres'
+ }
+}
+
+AUTHENTICATION_BACKENDS = [
+ "django.contrib.auth.backends.ModelBackend",
+ "taccsite_cms.remote_cms_auth.CorePortalAuthBackend",
+ "django_auth_ldap.backend.LDAPBackend"
+]
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
+''' LDAP Auth Settings '''
+AUTH_LDAP_SERVER_URI = "ldap://ldap.tacc.utexas.edu"
+AUTH_LDAP_CONNECTION_OPTIONS = {ldap.OPT_REFERRALS: 0}
+AUTH_LDAP_START_TLS = True
+AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True
+AUTH_LDAP_BIND_DN = ""
+AUTH_LDAP_BIND_PASSWORD = ""
+AUTH_LDAP_AUTHORIZE_ALL_USERS = True
+
+AUTH_LDAP_USER_SEARCH = LDAPSearch(
+ "ou=People,dc=tacc,dc=utexas,dc=edu", ldap.SCOPE_SUBTREE, "(uid=%(user)s)"
+)
+
+AUTH_LDAP_USER_ATTR_MAP = {
+ "first_name": "givenName",
+ "last_name": "sn",
+ "email": "mail",
+}
+
+SITE_ID = 1
+
+CMS_TEMPLATES = (
+ ('standard.html', 'Standard'),
+ ('fullwidth.html', 'Full Width'),
+)
+
+CMS_PERMISSION = True
+
+########################
+# GOOGLE ANALYTICS
+########################
+
+# To use during dev, Tracking Protection in browser needs to be turned OFF.
+GOOGLE_ANALYTICS_PROPERTY_ID = "UA-123ABC@%$&-#"
+GOOGLE_ANALYTICS_PRELOAD = True
+
+########################
+# CMS FORMS
+########################
+
+# Create CMS Forms
+# SEE: https://pypi.org/project/djangocms-forms/
+# SEE: https://www.google.com/recaptcha/admin/create
+DJANGOCMS_FORMS_RECAPTCHA_PUBLIC_KEY = ""
+DJANGOCMS_FORMS_RECAPTCHA_SECRET_KEY = ""
+
+########################
+# ELASTICSEARCH
+########################
+
+ES_AUTH = 'username:password'
+ES_HOSTS = 'http://elasticsearch:9200'
+ES_INDEX_PREFIX = 'cms-dev-{}'
+ES_DOMAIN = 'http://localhost:8000'
+
+"""
+Optional theming of CMS (certain themes may only affect some elements)
+Usage:
+- None (standard theme)
+- 'has-dark-logo'
+"""
+THEME = None
+
+TACC_BRANDING = [
+ "tacc",
+ "site_cms/img/org_logos/tacc-white.png",
+ "branding-tacc",
+ "https://www.tacc.utexas.edu/",
+ "_blank",
+ "TACC Logo",
+ "anonymous",
+ "True"
+]
+
+UTEXAS_BRANDING = [
+ "utexas",
+ "site_cms/img/org_logos/utaustin-white.png",
+ "branding-utaustin",
+ "https://www.utexas.edu/",
+ "_blank",
+ "University of Texas at Austin Logo",
+ "anonymous",
+ "True"
+]
+
+NSF_BRANDING = [
+ "nsf",
+ "site_cms/img/org_logos/nsf-white.png",
+ "branding-nsf",
+ "https://www.nsf.gov/",
+ "_blank",
+ "NSF Logo",
+ "anonymous",
+ "True"
+]
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = current_secrets._SECRET_KEY
+BRANDING = [ TACC_BRANDING, UTEXAS_BRANDING ]
+
+LOGO = [
+ "portal",
+ "site_cms/img/org_logos/portal.png",
+ "",
+ "/",
+ "_self",
+ "Portal Logo",
+ "anonymous",
+ "True"
+]
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = current_secrets._DEBUG
+FAVICON = {
+ "img_file_src": "site_cms/img/favicons/favicon.ico"
+}
-# Host Access.
-ALLOWED_HOSTS = current_secrets._ALLOWED_HOSTS
+INCLUDES_CORE_PORTAL = True
-# Custom Branding.
-THEME = current_secrets._THEME if hasattr(current_secrets, '_THEME') else None
-BRANDING = current_secrets._BRANDING
-LOGO = current_secrets._LOGO
-FAVICON = current_secrets._FAVICON
+LOGOUT_REDIRECT_URL='/'
-# Configure Portal.
-PORTAL = current_secrets._PORTAL
+## using container name to avoid cep.dev dns issues locally
+## this will need to be updated for dev/pprd/prod systems
+## for example, CEP_AUTH_VERIFICATION_ENDPOINT=https://dev.cep.tacc.utexas.edu
+CEP_AUTH_VERIFICATION_ENDPOINT='http://django:6000'
-# Optional features.
-FEATURES = current_secrets._FEATURES
+########################
+# CLIENT BUILD SETTINGS
+########################
# Application definition
ROOT_URLCONF = 'taccsite_cms.urls'
@@ -109,9 +185,6 @@ def getsecrets():
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(DATA_DIR, 'static')
-if CONSOLE_LOG_ENABLED:
- print("--> Variable STATIC_ROOT: ", STATIC_ROOT)
-
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'taccsite_cms', 'static'),
# os.path.join(BASE_DIR, 'taccsite_cms', 'en', 'static'),
@@ -119,16 +192,10 @@ def getsecrets():
os.path.join(BASE_DIR, 'taccsite_custom', '*', 'static')
))
-if CONSOLE_LOG_ENABLED:
- print("--> Variable STATICFILES_DIRS: ", STATICFILES_DIRS)
-
# User Uploaded Files Location.
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(DATA_DIR, 'media')
-if CONSOLE_LOG_ENABLED:
- print("--> Variable MEDIA_ROOT: ", MEDIA_ROOT)
-
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
@@ -139,7 +206,6 @@ def getsecrets():
) + [
os.path.join(BASE_DIR, 'taccsite_cms', 'templates')
],
- # 'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
@@ -169,9 +235,6 @@ def getsecrets():
},
]
-if CONSOLE_LOG_ENABLED:
- print("--> Variable TEMPLATES: ", TEMPLATES)
-
MIDDLEWARE = [
'cms.middleware.utils.ApphookReloadMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -207,10 +270,8 @@ def getsecrets():
'djangocms_text_ckeditor',
'filer',
'easy_thumbnails',
- # 'djangocms_audio',
'djangocms_column',
'djangocms_file',
- # 'djangocms_forms', # FP-416: Pending full support
'djangocms_link',
'djangocms_picture',
'djangocms_style',
@@ -235,15 +296,10 @@ def getsecrets():
'djangocms_bootstrap4.contrib.bootstrap4_utilities',
'haystack',
'aldryn_apphooks_config',
- # For faster testing, disable migrations during database creation
- # SEE: https://stackoverflow.com/a/37150997
'test_without_migrations',
'taccsite_cms',
- # Restore djangocms plugins that bootstrap4 hides
'taccsite_cms.contrib.bootstrap4_djangocms_link',
'taccsite_cms.contrib.bootstrap4_djangocms_picture',
- # TODO: Extract TACC CMS UI components into pip-installable plugins
- # FAQ: The djangocms_bootstrap4 library can serve as an example
'taccsite_cms.contrib.taccsite_sample',
'taccsite_cms.contrib.taccsite_system_monitor',
'taccsite_cms.contrib.taccsite_data_list'
@@ -267,80 +323,17 @@ def get_subdirs_as_module_names(path):
# Append CMS project paths as module names to INSTALLED_APPS
# FAQ: This automatically looks into `/taccsite_custom` and creates an "App" for each directory within
CUSTOM_CMS_DIR = os.path.join(BASE_DIR, 'taccsite_custom')
+
INSTALLED_APPS_APPEND = get_subdirs_as_module_names(CUSTOM_CMS_DIR)
INSTALLED_APPS = INSTALLED_APPS + INSTALLED_APPS_APPEND
-
-if CONSOLE_LOG_ENABLED:
- print("--> Variable INSTALLED_APPS: ", INSTALLED_APPS)
-
-AUTHENTICATION_BACKENDS = [
- "django.contrib.auth.backends.ModelBackend",
-]
-
-if LDAP_ENABLED:
- AUTHENTICATION_BACKENDS.insert(0,
- "django_auth_ldap.backend.LDAPBackend"
- )
-
- ''' LDAP Auth Settings '''
- AUTH_LDAP_SERVER_URI = "ldap://ldap.tacc.utexas.edu"
- AUTH_LDAP_CONNECTION_OPTIONS = {ldap.OPT_REFERRALS: 0}
- AUTH_LDAP_START_TLS = True
- AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True
-
- AUTH_LDAP_BIND_DN = ""
- AUTH_LDAP_BIND_PASSWORD = ""
- AUTH_LDAP_USER_SEARCH = LDAPSearch(
- "ou=People,dc=tacc,dc=utexas,dc=edu", ldap.SCOPE_SUBTREE, "(uid=%(user)s)"
- )
-
- AUTH_LDAP_AUTHORIZE_ALL_USERS = True
-
- AUTH_LDAP_USER_ATTR_MAP = {
- "first_name": "givenName",
- "last_name": "sn",
- "email": "mail",
- }
-
- '''
- # More customizations
-
- AUTH_LDAP_REQUIRE_GROUP = "cn=TACC-ACI-WMA,ou=Groups,dc=tacc,dc=utexas,dc=edu"
- AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
- "ou=Groups,dc=tacc,dc=utexas,dc=edu",
- ldap.SCOPE_SUBTREE,
- "(objectClass=groupOfUniqueNames)",
- )
- AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr="cn")
- '''
- ''' End LDAP Auth Settings '''
-
-if getattr(current_secrets, '_CACHES', None):
- CACHES = secrets._CACHES # Are we actually using this setting?
-
-DATABASES = current_secrets._DATABASES
-
MIGRATION_MODULES = { }
-
-# SSL Setup.
-# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
-# SECURE_SSL_REDIRECT = True
-# SESSION_COOKIE_SECURE = True
-# CSRF_COOKIE_SECURE = True
-
-# Internationalization
-# https://docs.djangoproject.com/en/2.2/topics/i18n/
-
LANGUAGE_CODE = 'en'
TIME_ZONE = 'America/Chicago'
USE_I18N = True
USE_L10N = True
USE_TZ = True
-# DjangoCMS Setup.
-SITE_ID = current_secrets._SITE_ID
-
LANGUAGES = (
# Customize this
('en', gettext('en')),
@@ -364,7 +357,6 @@ def get_subdirs_as_module_names(path):
},
}
-CMS_TEMPLATES = current_secrets._CMS_TEMPLATES
CMS_PERMISSION = True
CMS_PLACEHOLDER_CONF = {}
@@ -376,52 +368,6 @@ def get_subdirs_as_module_names(path):
'easy_thumbnails.processors.filters'
)
-
-# FEATURES.
-if CONSOLE_LOG_ENABLED:
- print("--> Variable FEATURES: ")
- for feature in FEATURES:
- print(feature + ": ", FEATURES[feature])
-
-if current_secrets._FEATURES['blog']:
- # Install required apps
- INSTALLED_APPS += [
- # Blog/News
- # 'filer', # Already added
- # 'easy_thumbnails', # Already added
- 'parler',
- 'taggit',
- 'taggit_autosuggest',
- 'meta', # also supports `djangocms_page_meta`
- 'sortedm2m',
- 'djangocms_blog',
-
- # Metadata
- 'djangocms_page_meta',
- ]
-
- # Metadata: Configure
- META_SITE_PROTOCOL = 'http'
- META_USE_SITES = True
- META_USE_OG_PROPERTIES = True
- META_USE_TWITTER_PROPERTIES = True
- META_USE_GOOGLEPLUS_PROPERTIES = True # django-meta 1.x+
- # META_USE_SCHEMAORG_PROPERTIES=True # django-meta 2.x+
-
- # Blog/News: Set custom paths for templates
- BLOG_PLUGIN_TEMPLATE_FOLDERS = (
- ('plugins/default', 'Default template'), # i.e. `templates/djangocms_blog/plugins/default/`
- ('plugins/default-clone', 'Clone of default template'), # i.e. `templates/djangocms_blog/plugins/default-clone/`
- )
-
- # Blog/News: Change default values for the auto-setup of one `BlogConfig`
- # SEE: https://github.com/nephila/djangocms-blog/issues/629
- BLOG_AUTO_SETUP = True
- BLOG_AUTO_HOME_TITLE ='Home'
- BLOG_AUTO_BLOG_TITLE = 'News'
- BLOG_AUTO_APP_TITLE = 'News'
-
-
DJANGOCMS_PICTURE_NESTING = True
DJANGOCMS_PICTURE_RESPONSIVE_IMAGES = True
DJANGOCMS_PICTURE_RESPONSIVE_IMAGES_VIEWPORT_BREAKPOINTS = [
@@ -437,39 +383,19 @@ def get_subdirs_as_module_names(path):
FILE_UPLOAD_PERMISSIONS = 0o644
FILE_UPLOAD_MAX_MEMORY_SIZE = 20000000 # 20MB
-# Custom picture templates - if required.
-# DJANGOCMS_PICTURE_TEMPLATES = [
-# ('background', _('Background image')), # Need to design these first!
-# ]
-
DJANGOCMS_AUDIO_ALLOWED_EXTENSIONS = ['mp3', 'ogg', 'wav']
-# Custom audio templates - if required.
-# DJANGOCMS_AUDIO_TEMPLATES = [
-# ('feature', _('Featured Version')),
-# ]
# Djangocms Forms Settings.
# SEE: https://github.com/mishbahr/djangocms-forms#configuration
DJANGOCMS_FORMS_PLUGIN_MODULE = ('Generic')
DJANGOCMS_FORMS_PLUGIN_NAME = ('Form')
-# DJANGOCMS_FORMS_DEFAULT_TEMPLATE = 'djangocms_forms/form_template/default.html'
+
DJANGOCMS_FORMS_TEMPLATES = (
('djangocms_forms/form_template/default.html', ('Default')),
)
DJANGOCMS_FORMS_USE_HTML5_REQUIRED = False
-# DJANGOCMS_FORMS_WIDGET_CSS_CLASSES = {'__all__': ('form-control', ) }
-DJANGOCMS_FORMS_REDIRECT_DELAY = 10000 # 10 seconds
-DJANGOCMS_FORMS_RECAPTCHA_PUBLIC_KEY = current_secrets._DJANGOCMS_FORMS_RECAPTCHA_PUBLIC_KEY
-DJANGOCMS_FORMS_RECAPTCHA_SECRET_KEY = current_secrets._DJANGOCMS_FORMS_RECAPTCHA_SECRET_KEY
-
-# Google Analytics.
-GOOGLE_ANALYTICS_PROPERTY_ID = current_secrets._GOOGLE_ANALYTICS_PROPERTY_ID
-GOOGLE_ANALYTICS_PRELOAD = current_secrets._GOOGLE_ANALYTICS_PRELOAD
-
-# SETTINGS VARIABLE EXPORTS.
-# Use a custom namespace (using default settings.VARIABLE configuration)
-SETTINGS_EXPORT_VARIABLE_NAME = 'settings'
+DJANGOCMS_FORMS_REDIRECT_DELAY = 1
# Elasticsearch Indexing
HAYSTACK_ROUTERS = ['aldryn_search.router.LanguageRouter',]
@@ -479,28 +405,42 @@ def get_subdirs_as_module_names(path):
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
- 'URL': current_secrets._ES_HOSTS,
- 'INDEX_NAME': current_secrets._ES_INDEX_PREFIX.format('cms'),
- 'KWARGS': {'http_auth': current_secrets._ES_AUTH }
+ 'URL': ES_HOSTS,
+ 'INDEX_NAME': 'cms',
+ 'KWARGS': {'http_auth': ES_AUTH }
}
}
-ES_DOMAIN = current_secrets._ES_DOMAIN
+SETTINGS_EXPORT_VARIABLE_NAME = 'settings'
+
+FEATURES = ''
+
+try:
+ from taccsite_cms.settings_custom import *
+except:
+ None
+ # do nothing
+
+try:
+ from taccsite_cms.secrets import *
+except:
+ None
+ # do nothing
+
+try:
+ from taccsite_cms.settings_local import *
+except:
+ None
+ # do nothing
-# Exported settings.
SETTINGS_EXPORT = [
'DEBUG',
+ 'FEATURES',
'THEME',
'BRANDING',
'LOGO',
'FAVICON',
- 'PORTAL',
- 'FEATURES',
+ 'INCLUDES_CORE_PORTAL',
'GOOGLE_ANALYTICS_PROPERTY_ID',
'GOOGLE_ANALYTICS_PRELOAD'
]
-
-if CONSOLE_LOG_ENABLED:
- print("--> Variable SETTINGS_EXPORT: ")
- for setting in SETTINGS_EXPORT:
- print(setting)
diff --git a/taccsite_cms/settings_custom.example.py b/taccsite_cms/settings_custom.example.py
new file mode 100644
index 000000000..6ea8dac74
--- /dev/null
+++ b/taccsite_cms/settings_custom.example.py
@@ -0,0 +1,43 @@
+
+'''
+
+settings_custom.py file can be used to override default values in settings.py
+
+The settings_custom.py file is loaded after default settings but before settings assignment is complete,
+giving us the opportunity to override settings in either settings_custom.py (usually set in custom sites)
+or in settings_local.py (usually used in a local dev environment).
+
+To override a setting,
+simply copy/paste the default settings and set the new/custom values
+
+If a setting override is for a custom site in an existing submodule, the change is made in
+the settings_custom.py file of that submodules site directory and (if not a secret) can be committed
+
+
+Unless modifying default behavior for the default cms and all custom sites (which probably means that
+setting should be in the settings.py file), the settings_custom.py file that should be modified is
+the one in the appropriate taccsite_custom site directory.
+
+'''
+
+# For example if we want to change LDAP auth settings for a custome site, let's say frontera-cms
+# we simply copy the setting from settings.py, and
+# assign the new value in "Core-CMS/taccsite_custom/frontera-cms/settings_custom.py"
+''' Example LDAP Auth Setting change where we just changing the ldap url '''
+AUTH_LDAP_SERVER_URI = "ldap://cluster.ldap.tacc.utexas.edu"
+
+#The same goes for other more commonly customized values like below
+# A customization to this default would be applied in settings_custom.py of the appropriate custom site
+PORTAL_LOGO = [
+ "portal",
+ "site_cms/img/org_logos/portal.png",
+ "",
+ "/",
+ "_self",
+ "Portal Logo",
+ "anonymous",
+ "True"
+]
+
+LOGO = PORTAL_LOGO
+
diff --git a/taccsite_cms/settings_to_json.py b/taccsite_cms/settings_to_json.py
index 19935ebd9..b99776e76 100644
--- a/taccsite_cms/settings_to_json.py
+++ b/taccsite_cms/settings_to_json.py
@@ -14,7 +14,7 @@
# Create JSON
setting_names = ["THEME"]
settings_export = {}
-# FAQ: The print() statements in settings.py would corrupt the JSON
+# FAQ: Any print() statements in settings.py would corrupt the JSON
with suppress_stdout():
for setting_name in setting_names:
settings_export[setting_name] = getattr(settings, setting_name)
diff --git a/taccsite_cms/static/site_cms/css/src/_imports/trumps/s-header.css b/taccsite_cms/static/site_cms/css/src/_imports/trumps/s-header.css
index cf1ed70b1..5d2f24524 100644
--- a/taccsite_cms/static/site_cms/css/src/_imports/trumps/s-header.css
+++ b/taccsite_cms/static/site_cms/css/src/_imports/trumps/s-header.css
@@ -228,6 +228,10 @@ Styleguide Trumps.Scopes.Header
color: var(--global-color-primary--xx-light);
background-color: var(--global-color-primary--xx-dark);
+
+ /* !!!: Missing env() var `--header-major-border-color` */
+ /* To hide border, set this in theme to match `--header-bkgd-color` value */
+ /* border-bottom: 1px solid env(--header-major-border-color); */
border-bottom: 1px solid var(--global-color-primary--xx-light);
}
diff --git a/taccsite_cms/static/site_cms/css/src/_themes/TODO.md b/taccsite_cms/static/site_cms/css/src/_themes/TODO.md
index 59610f835..999cbd85f 100644
--- a/taccsite_cms/static/site_cms/css/src/_themes/TODO.md
+++ b/taccsite_cms/static/site_cms/css/src/_themes/TODO.md
@@ -1,4 +1,4 @@
# TACC CMS - Stylesheets - Themes
- Migrate `/taccsite_cms/site_shared/css/src/_imports/settings/*` to theme data.
-- Support one theme extending another theme (the default or another).
+- Support one theme extending another theme (default theme or another theme).
diff --git a/taccsite_cms/templates/assets_site_delayed.html b/taccsite_cms/templates/assets_site_delayed.html
index a7392c21b..6d9df5ff3 100644
--- a/taccsite_cms/templates/assets_site_delayed.html
+++ b/taccsite_cms/templates/assets_site_delayed.html
@@ -18,7 +18,7 @@
{# FAQ: Not loaded in `assets_font.html` because these is NOT font for content which should avoid FOUT, FOIT, FOFT; but decorative, thus superfluous, icons #}
-{% if settings.PORTAL %}
-
+{% if settings.INCLUDES_CORE_PORTAL %}
+
{% endif %}
diff --git a/taccsite_cms/templates/header.html b/taccsite_cms/templates/header.html
index e457ad0e8..32c4c079c 100644
--- a/taccsite_cms/templates/header.html
+++ b/taccsite_cms/templates/header.html
@@ -9,7 +9,7 @@
{# NOTE: `navbar-expand-*` maps to a `media-queries.css`'s `--nav-*` value #}
{# CAVEAT: The mobile nav CSS can NOT support conditional `navbar-expand-*` #}
-