# Copyright The IETF Trust 2007-2022, All Rights Reserved
# -*- coding: utf-8 -*-


# Django settings for ietf project.
# BASE_DIR and "settings_local" are from
# http://code.djangoproject.com/wiki/SplitSettings

import os
import sys
import datetime
import warnings
from typing import Any, Dict, List, Tuple # pyflakes:ignore

warnings.simplefilter("always", DeprecationWarning)
warnings.filterwarnings("ignore", message="'urllib3\[secure\]' extra is deprecated")
warnings.filterwarnings("ignore", message="The logout\(\) view is superseded by")
warnings.filterwarnings("ignore", message="Report.file_reporters will no longer be available in Coverage.py 4.2", module="coverage.report")
warnings.filterwarnings("ignore", message="{% load staticfiles %} is deprecated")
warnings.filterwarnings("ignore", message="Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated", module="bleach")
warnings.filterwarnings("ignore", message="HTTPResponse.getheader\(\) is deprecated", module='selenium.webdriver')
try:
    import syslog
    syslog.openlog(str("datatracker"), syslog.LOG_PID, syslog.LOG_USER)
except ImportError:
    pass

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.abspath(BASE_DIR + "/.."))

from ietf import __version__
import debug

DEBUG = True
debug.debug = DEBUG

DEBUG_AGENDA = False

# Valid values:
# 'production', 'test', 'development'
# Override this in settings_local.py if it's not the desired setting:
SERVER_MODE = 'development'

# Domain name of the IETF
IETF_DOMAIN = 'ietf.org'

ADMINS = [
#    ('Henrik Levkowetz', 'henrik@levkowetz.com'),
    ('Robert Sparks', 'rjsparks@nostrum.com'),
#    ('Ole Laursen', 'olau@iola.dk'),
    ('Ryan Cross', 'rcross@amsl.com'),
    ('Glen Barney', 'glen@amsl.com'),
    ('Maddy Conner', 'maddy@amsl.com'),
    ('Kesara Rathnayaka', 'krathnayake@ietf.org'),
]                                       # type: List[Tuple[str, str]]

BUG_REPORT_EMAIL = "datatracker-project@ietf.org"

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.SHA1PasswordHasher',
    'django.contrib.auth.hashers.CryptPasswordHasher',
]

ALLOWED_HOSTS = [".ietf.org", ".ietf.org.", "209.208.19.216", "4.31.198.44", "127.0.0.1", "localhost", ]

# Server name of the tools server
TOOLS_SERVER = 'tools.' + IETF_DOMAIN

# Override this in the settings_local.py file:
SERVER_EMAIL = 'Django Server <django-project@' + IETF_DOMAIN + '>'

DEFAULT_FROM_EMAIL = 'IETF Secretariat <ietf-secretariat-reply@' + IETF_DOMAIN + '>'
UTILS_ON_BEHALF_EMAIL = 'noreply@' + IETF_DOMAIN
UTILS_FROM_EMAIL_DOMAINS = [ 'ietf.org', 'iab.org', ]

MANAGERS = ADMINS

DATABASES = {
    'default': {
        'NAME': 'ietf_utf8',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'ietf',
        #'PASSWORD': 'ietf',
        'OPTIONS': {
            'sql_mode': 'STRICT_TRANS_TABLES',
            'init_command': 'SET storage_engine=MyISAM; SET names "utf8"'
        },
    },
}

DATABASE_TEST_OPTIONS = {
    # Comment this out if your database doesn't support InnoDB
    'init_command': 'SET storage_engine=InnoDB',
}

# Local time zone for this installation. Choices can be found here:
# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
# although not all variations may be possible on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'PST8PDT'

# Language code for this installation. All choices can be found here:
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
# http://blogs.law.harvard.edu/tech/stories/storyReader$15
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

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

USE_TZ = True

if SERVER_MODE == 'production':
    MEDIA_ROOT = '/a/www/www6s/lib/dt/media/'
    MEDIA_URL  = 'https://www.ietf.org/lib/dt/media/'
    PHOTOS_DIRNAME = 'photo'
    PHOTOS_DIR = os.path.join(MEDIA_ROOT, PHOTOS_DIRNAME)
else:
    MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'media')
    MEDIA_URL = '/media/'
    PHOTOS_DIRNAME = 'photo'
    PHOTOS_DIR = os.path.join(MEDIA_ROOT, PHOTOS_DIRNAME)

OLD_PHOTO_DIRS = [
    '/a/www/www6/wg/images',
    '/a/www/www6/iesg/bio/photo',
    '/a/www/iab/wp-content/IAB-uploads/2010/10/',
    '/a/www/iab/wp-content/IAB-uploads/2011/05/',
    '/a/www/iab/wp-content/IAB-uploads/2014/02/',
    '/a/www/iab/wp-content/IAB-uploads/2015/02/',
    '/a/www/iab/wp-content/IAB-uploads/2015/03/',
    '/a/www/iab/wp-content/IAB-uploads/2015/06/',
    '/a/www/iab/wp-content/IAB-uploads/2015/08/',
    '/a/www/iab/wp-content/IAB-uploads/2016/03/',
]

IETF_HOST_URL = 'https://www.ietf.org/'
IETF_ID_URL = IETF_HOST_URL + 'id/' # currently unused
IETF_ID_ARCHIVE_URL = IETF_HOST_URL + 'archive/id/'
IETF_AUDIO_URL = IETF_HOST_URL + 'audio/'

IETF_NOTES_URL = 'https://notes.ietf.org/'  # HedgeDoc base URL

# Absolute path to the directory static files should be collected to.
# Example: "/var/www/example.com/static/"


SERVE_CDN_PHOTOS = True

SERVE_CDN_FILES_LOCALLY_IN_DEV_MODE = True

# URL to use when referring to static files located in STATIC_ROOT.
if SERVER_MODE != 'production' and SERVE_CDN_FILES_LOCALLY_IN_DEV_MODE:
    STATIC_URL = "/static/"
    STATIC_ROOT = os.path.abspath(BASE_DIR + "/../static/")
else:
    STATIC_URL = "https://www.ietf.org/lib/dt/%s/"%__version__
    STATIC_ROOT = "/a/www/www6s/lib/dt/%s/"%__version__

# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)

WSGI_APPLICATION = "ietf.wsgi.application"

AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', )

FILE_UPLOAD_PERMISSIONS = 0o644          

# ------------------------------------------------------------------------
# Django/Python Logging Framework Modifications

# Filter out "Invalid HTTP_HOST" emails
# Based on http://www.tiwoc.de/blog/2013/03/django-prevent-email-notification-on-suspiciousoperation/
from django.core.exceptions import SuspiciousOperation
def skip_suspicious_operations(record):
    if record.exc_info:
        exc_value = record.exc_info[1]
        if isinstance(exc_value, SuspiciousOperation):
            return False
    return True

# Filter out UreadablePostError:
from django.http import UnreadablePostError
def skip_unreadable_post(record):
    if record.exc_info:
        exc_type, exc_value = record.exc_info[:2] # pylint: disable=unused-variable
        if isinstance(exc_value, UnreadablePostError):
            return False
    return True

# Copied from DEFAULT_LOGGING as of Django 1.10.5 on 22 Feb 2017, and modified
# to incorporate html logging, invalid http_host filtering, and more.
# Changes from the default has comments.

# The Python logging flow is as follows:
# (see https://docs.python.org/2.7/howto/logging.html#logging-flow)
#
#   Init: get a Logger: logger = logging.getLogger(name)
#
#   Logging call, e.g. logger.error(level, msg, *args, exc_info=(...), extra={...})
#   --> Logger (discard if level too low for this logger)
#       (create log record from level, msg, args, exc_info, extra)
#       --> Filters (discard if any filter attach to logger rejects record)
#           --> Handlers (discard if level too low for handler)
#               --> Filters (discard if any filter attached to handler rejects record)
#                   --> Formatter (format log record and emit)
#

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    #
    'loggers': {
        'django': {
            'handlers': ['debug_console', 'mail_admins'],
            'level': 'INFO',
        },
        'django.request': {
            'handlers': ['debug_console'],
            'level': 'ERROR',
        },
        'django.server': {
            'handlers': ['django.server'],
            'level': 'INFO',
        },
        'django.security': {
	    'handlers': ['debug_console', ],
            'level': 'INFO',
        },
 	'oidc_provider': {
	    'handlers': ['debug_console', ],
	    'level': 'DEBUG',
	},
    },
    #
    # No logger filters
    #
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'plain',
        },
        'syslog': {
            'level': 'DEBUG',
            'class': 'logging.handlers.SysLogHandler',
            'facility': 'user',
            'formatter': 'plain',
            'address': '/dev/log',
        },
        'debug_console': {
            # Active only when DEBUG=True
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'plain',
        },
        'django.server': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'django.server',
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': [
                'require_debug_false',
                'skip_suspicious_operations', # custom
                'skip_unreadable_posts', # custom
            ],
            'class': 'django.utils.log.AdminEmailHandler',
            'include_html': True,       # non-default
        }
    },
    #
    # All these are used by handlers
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
        # custom filter, function defined above:
        'skip_suspicious_operations': {
            '()': 'django.utils.log.CallbackFilter',
            'callback': skip_suspicious_operations,
        },
        # custom filter, function defined above:
        'skip_unreadable_posts': {
            '()': 'django.utils.log.CallbackFilter',
            'callback': skip_unreadable_post,
        },
    },
    # And finally the formatters
    'formatters': {
        'django.server': {
            '()': 'django.utils.log.ServerFormatter',
            'format': '[%(server_time)s] %(message)s',
        },
        'plain': {
            'style': '{',
            'format': '{levelname}: {name}:{lineno}: {message}',
        },
    },
}

# This should be overridden by settings_local for any logger where debug (or
# other) custom log settings are wanted.  Use "ietf/manage.py showloggers -l"
# to show registered loggers.  The content here should match the levels above
# and is shown as an example:
UTILS_LOGGER_LEVELS: Dict[str, str] = {
#    'django':           'INFO',
#    'django.server':    'INFO',
}

# End logging
# ------------------------------------------------------------------------


X_FRAME_OPTIONS = 'SAMEORIGIN'
CSRF_TRUSTED_ORIGINS = ['ietf.org', '*.ietf.org', 'meetecho.com', '*.meetecho.com', 'gather.town', '*.gather.town', ]
CSRF_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SECURE = True

# SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds: 2 weeks (django default)
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 4 # Age of cookie, in seconds: 4 weeks
SESSION_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SECURE = True

SESSION_EXPIRE_AT_BROWSER_CLOSE = False
# We want to use the JSON serialisation, as it's safer -- but there is /secr/
# code which stashes objects in the session that can't be JSON serialized.
# Switch when that code is rewritten.
#SESSION_SERIALIZER = "django.contrib.sessions.serializers.JSONSerializer"
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_SAVE_EVERY_REQUEST = True
SESSION_CACHE_ALIAS = 'sessions'

PREFERENCES_COOKIE_AGE = 60 * 60 * 24 * 365 * 50 # Age of cookie, in seconds: 50 years

TEMPLATES = [                           
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            BASE_DIR + "/templates",
            BASE_DIR + "/secr/templates",
        ],
        'OPTIONS': {
            'context_processors': [
                'django.contrib.auth.context_processors.auth',
                'django.template.context_processors.debug',     # makes 'sql_queries' available in templates
                'django.template.context_processors.i18n',
                'django.template.context_processors.request',
                'django.template.context_processors.media',
                #'django.template.context_processors.tz',
                'django.contrib.messages.context_processors.messages',
                'ietf.context_processors.server_mode',
#                'ietf.context_processors.debug_mark_queries_from_view',
#                'ietf.context_processors.sql_debug',
                'ietf.context_processors.revision_info',
                'ietf.context_processors.settings_info',
                'ietf.secr.context_processors.secr_revision_info',
                'ietf.context_processors.rfcdiff_base_url',
            ],
            'loaders': [
                ('django.template.loaders.cached.Loader', (
                    'django.template.loaders.filesystem.Loader',
                    'django.template.loaders.app_directories.Loader',
                )),
                'ietf.dbtemplate.template.Loader',
            ]
        },
    },
]                                       # type: List[Dict[str,Any]]

if DEBUG:
    TEMPLATES[0]['OPTIONS']['string_if_invalid'] = "** No value found for '%s' **"


MIDDLEWARE = [
    'django.middleware.csrf.CsrfViewMiddleware',
    'corsheaders.middleware.CorsMiddleware', # see docs on CORS_REPLACE_HTTPS_REFERER before using it
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.http.ConditionalGetMiddleware',
    'simple_history.middleware.HistoryRequestMiddleware',
    # comment in this to get logging of SQL insert and update statements:
    #'ietf.middleware.sql_log_middleware',
    'ietf.middleware.SMTPExceptionMiddleware',
    'ietf.middleware.Utf8ExceptionMiddleware',
    'ietf.middleware.redirect_trailing_period_middleware',
    'django_referrer_policy.middleware.ReferrerPolicyMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
 #   'csp.middleware.CSPMiddleware',
    'ietf.middleware.unicode_nfkc_normalization_middleware',
]

ROOT_URLCONF = 'ietf.urls'

DJANGO_VITE_ASSETS_PATH = os.path.join(BASE_DIR, 'static/dist-neue')
if DEBUG:
    DJANGO_VITE_MANIFEST_PATH = os.path.join(BASE_DIR, 'static/dist-neue/manifest.json')

# Additional locations of static files (in addition to each app's static/ dir)
STATICFILES_DIRS = (
    DJANGO_VITE_ASSETS_PATH,
    os.path.join(BASE_DIR, 'static/dist'),
    os.path.join(BASE_DIR, 'secr/static/dist'),
)

INSTALLED_APPS = [
    # Django apps
    'django.contrib.admin',
    'django.contrib.admindocs',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.humanize',
    'django.contrib.messages',
    'django.contrib.sessions',
    'django.contrib.sitemaps',
    'django.contrib.sites',
    'django.contrib.staticfiles',
    # External apps 
    'analytical',
    'django_vite',
    'django_bootstrap5',
    'django_celery_beat',
    'corsheaders',
    'django_markup',
    'django_password_strength',
    'form_utils',
    'oidc_provider',
    'simple_history',
    'tastypie',
    'widget_tweaks',
    # IETF apps
    'ietf.api',
    'ietf.community',
    'ietf.dbtemplate',
    'ietf.doc',
    'ietf.group',
    'ietf.idindex',
    'ietf.iesg',
    'ietf.ietfauth',
    'ietf.ipr',
    'ietf.liaisons',
    'ietf.mailinglists',
    'ietf.mailtrigger',
    'ietf.meeting',
    'ietf.message',
    'ietf.name',
    'ietf.nomcom',
    'ietf.person',
    'ietf.redirects',
    'ietf.release',
    'ietf.review',
    'ietf.stats',
    'ietf.submit',
    'ietf.sync',
    'ietf.utils',
    # IETF Secretariat apps
    'ietf.secr.announcement',
    'ietf.secr.areas',
    'ietf.secr.groups',
    'ietf.secr.meetings',
    'ietf.secr.proceedings',
    'ietf.secr.roles',
    'ietf.secr.rolodex',
    'ietf.secr.sreq',
    'ietf.secr.telechat',
]

try:
    import django_extensions            # pyflakes:ignore
    INSTALLED_APPS.append('django_extensions')
except ImportError:
    pass

# Settings for django-bootstrap5
# See https://django-bootstrap5.readthedocs.io/en/latest/settings.html
BOOTSTRAP5 = {
    # Label class to use in horizontal forms
    'horizontal_label_class': 'col-md-2 fw-bold',

    # Field class to use in horiozntal forms
    'horizontal_field_class': 'col-md-10',

    # Field class used for horizontal fields withut a label.
    'horizontal_field_offset_class': 'offset-md-2',

    # Set placeholder attributes to label if no placeholder is provided
    'set_placeholder': False,

    'required_css_class': 'required',
    'error_css_class': 'is-invalid',
    'success_css_class': 'is-valid',

    'field_renderers': {
        'default': 'ietf.utils.bootstrap.SeparateErrorsFromHelpTextFieldRenderer',
    },
}

# CORS settings
# See https://github.com/ottoyiu/django-cors-headers/
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = ( 'GET', 'OPTIONS', )
CORS_URLS_REGEX = r'^(/api/.*|.*\.json|.*/json/?)$'

# Setting for django_referrer_policy.middleware.ReferrerPolicyMiddleware
REFERRER_POLICY = 'strict-origin-when-cross-origin'

# django.middleware.security.SecurityMiddleware 
SECURE_BROWSER_XSS_FILTER       = True
SECURE_CONTENT_TYPE_NOSNIFF     = True
SECURE_HSTS_INCLUDE_SUBDOMAINS  = True
#SECURE_HSTS_PRELOAD             = True             # Enable after testing
SECURE_HSTS_SECONDS             = 3600
#SECURE_REDIRECT_EXEMPT
#SECURE_SSL_HOST 
#SECURE_SSL_REDIRECT             = True

# Override this in your settings_local with the IP addresses relevant for you:
INTERNAL_IPS = (
# local
        '127.0.0.1',
        '::1',
)

# no slash at end
IDTRACKER_BASE_URL = "https://datatracker.ietf.org"
RFCDIFF_BASE_URL = "https://author-tools.ietf.org/iddiff"
IDNITS_BASE_URL = "https://author-tools.ietf.org/api/idnits"
IDNITS_SERVICE_URL = "https://author-tools.ietf.org/idnits"

# Content security policy configuration (django-csp)
CSP_DEFAULT_SRC = ("'self'", "'unsafe-inline'", f"data: {IDTRACKER_BASE_URL} https://www.ietf.org/ https://analytics.ietf.org/ https://fonts.googleapis.com/")

# The name of the method to use to invoke the test suite
TEST_RUNNER = 'ietf.utils.test_runner.IetfTestRunner'

# Fixtures which will be loaded before testing starts
GLOBAL_TEST_FIXTURES = [ 'names','ietf.utils.test_data.make_immutable_base_data',
    'nomcom_templates','proceedings_templates' ]

TEST_DIFF_FAILURE_DIR = "/tmp/test/failure/"

TEST_GHOSTDRIVER_LOG_PATH = "ghostdriver.log"

# These are regexes
TEST_URL_COVERAGE_EXCLUDE = [
    r"^\^admin/",
]

# These are filename globs.  They are fed directly to the coverage code checker.
TEST_CODE_COVERAGE_EXCLUDE_FILES = [
    "*/tests*",
    "*/admin.py",
    "*/factories.py",
    "*/migrations/*",
    "*/management/commands/*",
    "docker/*",
    "idindex/generate_all_id2_txt.py",
    "idindex/generate_all_id_txt.py",
    "idindex/generate_id_abstracts_txt.py",
    "idindex/generate_id_index_txt.py",
    "ietf/checks.py",
    "ietf/manage.py",
    "ietf/virtualenv-manage.py",
    "ietf/meeting/timedeltafield.py",   # Dead code, kept for a migration include
    "ietf/settings*",
    "ietf/utils/templatetags/debug_filters.py",
    "ietf/utils/test_runner.py",
    "ietf/name/generate_fixtures.py",
    "ietf/review/import_from_review_tool.py",
    "ietf/stats/backfill_data.py",
    "ietf/utils/patch.py",
    "ietf/utils/test_data.py",
]

# These are code line regex patterns
TEST_CODE_COVERAGE_EXCLUDE_LINES = [
    "coverage: *ignore",
    "debug",
    r"unreachable\([^)]*\)",
    "if settings.DEBUG",
    "if settings.TEST_CODE_COVERAGE_CHECKER",
    "if __name__ == .__main__.:",
]

# These are filename globs.  They are used by test_parse_templates() and
# get_template_paths()
TEST_TEMPLATE_IGNORE = [
    ".*",                             # dot-files
    "*~",                             # tilde temp-files
    "#*",                             # files beginning with a hashmark
    "500.html"                        # isn't loaded by regular loader, but checked by test_500_page()
]

TEST_COVERAGE_MAIN_FILE = os.path.join(BASE_DIR, "../release-coverage.json")
TEST_COVERAGE_LATEST_FILE = os.path.join(BASE_DIR, "../latest-coverage.json")

TEST_CODE_COVERAGE_CHECKER = None
if SERVER_MODE != 'production':
    import coverage
    TEST_CODE_COVERAGE_CHECKER = coverage.Coverage(source=[ BASE_DIR ], cover_pylib=False, omit=TEST_CODE_COVERAGE_EXCLUDE_FILES)

TEST_CODE_COVERAGE_REPORT_PATH = "coverage/"
TEST_CODE_COVERAGE_REPORT_URL = os.path.join(STATIC_URL, TEST_CODE_COVERAGE_REPORT_PATH, "index.html")
TEST_CODE_COVERAGE_REPORT_DIR = os.path.join(BASE_DIR, "static", TEST_CODE_COVERAGE_REPORT_PATH)
TEST_CODE_COVERAGE_REPORT_FILE = os.path.join(TEST_CODE_COVERAGE_REPORT_DIR, "index.html")

# WG Chair configuration
MAX_WG_DELEGATES = 3

# These states aren't available in forms with drop-down choices for new
# document state:
GROUP_STATES_WITH_EXTRA_PROCESSING = ["sub-pub", "rfc-edit", ]

# Review team related settings
GROUP_REVIEW_MAX_ITEMS_TO_SHOW_IN_REVIEWER_LIST = 10
GROUP_REVIEW_DAYS_TO_SHOW_IN_REVIEWER_LIST = 365

DATE_FORMAT = "Y-m-d"
DATETIME_FORMAT = "Y-m-d H:i T"

# Add reusable URL regexps here, for consistency.  No need to do so if the
# regex can reasonably be expected to be a unique one-off.
URL_REGEXPS = {
    "acronym": r"(?P<acronym>[-a-z0-9]+)",
    "bofreq": r"(?P<name>bofreq-[-a-z0-9]+)",
    "charter": r"(?P<name>charter-[-a-z0-9]+)",
    "date": r"(?P<date>\d{4}-\d{2}-\d{2})",
    "name": r"(?P<name>[A-Za-z0-9._+-]+?)",
    "document": r"(?P<document>[a-z][-a-z0-9]+)", # regular document names
    "rev": r"(?P<rev>[0-9]{1,2}(-[0-9]{2})?)",
    "owner": r"(?P<owner>[-A-Za-z0-9\'+._]+@[A-Za-z0-9-._]+)",
    "schedule_name": r"(?P<name>[A-Za-z0-9-:_]+)",
}

# Override this in settings_local.py if needed
# *_PATH variables ends with a slash/ .

#DOCUMENT_PATH_PATTERN = '/a/www/ietf-ftp/{doc.type_id}/'
DOCUMENT_PATH_PATTERN = '/a/ietfdata/doc/{doc.type_id}/'
INTERNET_DRAFT_PATH = '/a/ietfdata/doc/draft/repository'
INTERNET_DRAFT_PDF_PATH = '/a/www/ietf-datatracker/pdf/'
RFC_PATH = '/a/www/ietf-ftp/rfc/'
CHARTER_PATH = '/a/ietfdata/doc/charter/'
BOFREQ_PATH = '/a/ietfdata/doc/bofreq/'
CONFLICT_REVIEW_PATH = '/a/ietfdata/doc/conflict-review'
STATUS_CHANGE_PATH = '/a/ietfdata/doc/status-change'
AGENDA_PATH = '/a/www/www6s/proceedings/'
MEETINGHOST_LOGO_PATH = AGENDA_PATH  # put these in the same place as other proceedings files
IPR_DOCUMENT_PATH = '/a/www/ietf-ftp/ietf/IPR/'
IESG_TASK_FILE = '/a/www/www6/iesg/internal/task.txt'
IESG_ROLL_CALL_FILE = '/a/www/www6/iesg/internal/rollcall.txt'
IESG_ROLL_CALL_URL = 'https://www6.ietf.org/iesg/internal/rollcall.txt'
IESG_MINUTES_FILE = '/a/www/www6/iesg/internal/minutes.txt'
IESG_MINUTES_URL = 'https://www6.ietf.org/iesg/internal/minutes.txt'
IESG_WG_EVALUATION_DIR = "/a/www/www6/iesg/evaluation"
# Move drafts to this directory when they expire
INTERNET_DRAFT_ARCHIVE_DIR = '/a/ietfdata/doc/draft/collection/draft-archive/'
# The following directory contains linked copies of all drafts, but don't
# write anything to this directory -- its content is maintained by ghostlinkd:
INTERNET_ALL_DRAFTS_ARCHIVE_DIR = '/a/ietfdata/doc/draft/archive'
MEETING_RECORDINGS_DIR = '/a/www/audio'
DERIVED_DIR = '/a/ietfdata/derived'

DOCUMENT_FORMAT_ALLOWLIST = ["txt", "ps", "pdf", "xml", "html", ]

# Mailing list info URL for lists hosted on the IETF servers
MAILING_LIST_INFO_URL = "https://www.ietf.org/mailman/listinfo/%(list_addr)s"
MAILING_LIST_ARCHIVE_URL = "https://mailarchive.ietf.org"

# Liaison Statement Tool settings (one is used in DOC_HREFS below)
LIAISON_UNIVERSAL_FROM = 'Liaison Statement Management Tool <statements@' + IETF_DOMAIN + '>'
LIAISON_ATTACH_PATH = '/a/www/ietf-datatracker/documents/LIAISON/' # should end in a slash
LIAISON_ATTACH_URL = 'https://www.ietf.org/lib/dt/documents/LIAISON/' # should end in a slash, location should have a symlink to LIAISON_ATTACH_PATH

# Ideally, more of these would be local -- but since we don't support
# versions right now, we'll point to external websites
DOC_HREFS = {
    "charter":  "https://www.ietf.org/charter/{doc.name}-{doc.rev}.txt",
    "draft":    "https://www.ietf.org/archive/id/{doc.name}-{doc.rev}.txt",
    "rfc":      "https://www.rfc-editor.org/rfc/rfc{doc.rfcnum}.txt",
    "slides": "https://www.ietf.org/slides/{doc.name}-{doc.rev}",
    "procmaterials": "https://www.ietf.org/procmaterials/{doc.name}-{doc.rev}",
    "conflrev": "https://www.ietf.org/cr/{doc.name}-{doc.rev}.txt",
    "statchg": "https://www.ietf.org/sc/{doc.name}-{doc.rev}.txt",
    "liaison": "%s{doc.uploaded_filename}" % LIAISON_ATTACH_URL,
    "liai-att": "%s{doc.uploaded_filename}" % LIAISON_ATTACH_URL,
}

# Valid MIME types for cases where text is uploaded and immediately extracted,
# e.g. a charter or a review. Must be a tuple, not a list.
DOC_TEXT_FILE_VALID_UPLOAD_MIME_TYPES = ('text/plain', 'text/markdown', 'text/x-rst', 'text/x-markdown', )

# Age limit before action holders are flagged in the document display
DOC_ACTION_HOLDER_AGE_LIMIT_DAYS = 20

# Override this in settings_local.py if needed
CACHE_MIDDLEWARE_SECONDS = 300
CACHE_MIDDLEWARE_KEY_PREFIX = ''

# The default with no CACHES setting is 'django.core.cache.backends.locmem.LocMemCache'
# This setting is possibly overridden further down, after the import of settings_local
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
        'VERSION': __version__,
        'KEY_PREFIX': 'ietf:dt',
    },
    'sessions': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
        # No release-specific VERSION setting.
        'KEY_PREFIX': 'ietf:dt',
    },
    'htmlized': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/a/cache/datatracker/htmlized',
        'OPTIONS': {
            'MAX_ENTRIES': 100000,      # 100,000
        },
    },
    'pdfized': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/a/cache/datatracker/pdfized',
        'OPTIONS': {
            'MAX_ENTRIES': 100000,      # 100,000
        },
    },
    'slowpages': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/a/cache/datatracker/slowpages',
        'OPTIONS': {
            'MAX_ENTRIES': 5000,
        },
    },
}

HTMLIZER_VERSION = 1
HTMLIZER_URL_PREFIX = "/doc/html"
HTMLIZER_CACHE_TIME = 60*60*24*14       # 14 days
PDFIZER_CACHE_TIME = HTMLIZER_CACHE_TIME
PDFIZER_URL_PREFIX = IDTRACKER_BASE_URL+"/doc/pdf"

# Email settings
IPR_EMAIL_FROM = 'ietf-ipr@ietf.org'
AUDIO_IMPORT_EMAIL = ['ietf@meetecho.com']
SESSION_REQUEST_FROM_EMAIL = 'IETF Meeting Session Request Tool <session-request@ietf.org>' 

SECRETARIAT_SUPPORT_EMAIL = "support@ietf.org"
SECRETARIAT_ACTION_EMAIL = "ietf-action@ietf.org"
SECRETARIAT_INFO_EMAIL = "ietf-info@ietf.org"

# Put real password in settings_local.py
IANA_SYNC_PASSWORD = "secret"
IANA_SYNC_CHANGES_URL = "https://datatracker.iana.org:4443/data-tracker/changes"
IANA_SYNC_PROTOCOLS_URL = "https://www.iana.org/protocols/"

RFC_TEXT_RSYNC_SOURCE="ftp.rfc-editor.org::rfcs-text-only"

RFC_EDITOR_SYNC_PASSWORD="secret"
RFC_EDITOR_SYNC_NOTIFICATION_URL = "https://www.rfc-editor.org/parser/parser.php"
RFC_EDITOR_GROUP_NOTIFICATION_EMAIL = "webmaster@rfc-editor.org"
#RFC_EDITOR_GROUP_NOTIFICATION_URL = "https://www.rfc-editor.org/notification/group.php"
RFC_EDITOR_QUEUE_URL = "https://www.rfc-editor.org/queue2.xml"
RFC_EDITOR_INDEX_URL = "https://www.rfc-editor.org/rfc/rfc-index.xml"
RFC_EDITOR_ERRATA_JSON_URL = "https://www.rfc-editor.org/errata.json"
RFC_EDITOR_ERRATA_URL = "https://www.rfc-editor.org/errata_search.php?rfc={rfc_number}"
RFC_EDITOR_INLINE_ERRATA_URL = "https://www.rfc-editor.org/rfc/inline-errata/rfc{rfc_number}.html"
RFC_EDITOR_INFO_BASE_URL = "https://www.rfc-editor.org/info/"

# NomCom Tool settings
ROLODEX_URL = ""
NOMCOM_PUBLIC_KEYS_DIR = '/a/www/nomcom/public_keys/'
NOMCOM_FROM_EMAIL = 'nomcom-chair-{year}@ietf.org'
OPENSSL_COMMAND = '/usr/bin/openssl'
DAYS_TO_EXPIRE_NOMINATION_LINK = ''
NOMINEE_FEEDBACK_TYPES = ['comment', 'questio', 'nomina']

# SlideSubmission settings
SLIDE_STAGING_PATH = '/a/www/www6s/staging/'
SLIDE_STAGING_URL = 'https://www.ietf.org/staging/'

# ID Submission Tool settings
IDSUBMIT_FROM_EMAIL = 'IETF I-D Submission Tool <idsubmission@ietf.org>'
IDSUBMIT_ANNOUNCE_FROM_EMAIL = 'internet-drafts@ietf.org'
IDSUBMIT_ANNOUNCE_LIST_EMAIL = 'i-d-announce@ietf.org'

# Interim Meeting Tool settings
INTERIM_ANNOUNCE_FROM_EMAIL_DEFAULT = 'IESG Secretary <iesg-secretary@ietf.org>'
INTERIM_ANNOUNCE_FROM_EMAIL_PROGRAM = 'IAB Executive Administrative Manager <execd@iab.org>'
VIRTUAL_INTERIMS_REQUIRE_APPROVAL = False
INTERIM_SESSION_MINIMUM_MINUTES = 30
INTERIM_SESSION_MAXIMUM_MINUTES = 300

# Days from meeting to day of cut off dates on submit -- cutoff_time_utc is added to this
IDSUBMIT_DEFAULT_CUTOFF_DAY_OFFSET_00 = 13
IDSUBMIT_DEFAULT_CUTOFF_DAY_OFFSET_01 = 13
IDSUBMIT_DEFAULT_CUTOFF_TIME_UTC = datetime.timedelta(hours=23, minutes=59, seconds=59)
IDSUBMIT_DEFAULT_CUTOFF_WARNING_DAYS = datetime.timedelta(days=21)

# 14 Jun 2017: New convention: prefix settings with the app name to which
# they (mainly) belong.  So here, SUBMIT_, rather than IDSUBMIT_
SUBMIT_YANG_RFC_MODEL_DIR = '/a/www/ietf-ftp/yang/rfcmod/'
SUBMIT_YANG_DRAFT_MODEL_DIR = '/a/www/ietf-ftp/yang/draftmod/'
SUBMIT_YANG_IANA_MODEL_DIR = '/a/www/ietf-ftp/yang/ianamod/'
SUBMIT_YANG_CATALOG_MODEL_DIR = '/a/www/ietf-ftp/yang/catalogmod/'

IDSUBMIT_REPOSITORY_PATH = INTERNET_DRAFT_PATH
IDSUBMIT_STAGING_PATH = '/a/www/www6s/staging/'
IDSUBMIT_STAGING_URL = '//www.ietf.org/staging/'
IDSUBMIT_IDNITS_BINARY = '/a/www/ietf-datatracker/scripts/idnits'
SUBMIT_PYANG_COMMAND = 'pyang --verbose --ietf -p {libs} {model}'
SUBMIT_YANGLINT_COMMAND = 'yanglint --verbose -p {tmplib} -p {rfclib} -p {draftlib} -p {ianalib} -p {cataloglib} {model} -i'

SUBMIT_YANG_CATALOG_MODULEARG = "modules[]={module}"
SUBMIT_YANG_CATALOG_IMPACT_URL = "https://www.yangcatalog.org/yang-search/impact_analysis.php?{moduleargs}&recurse=0&rfcs=1&show_subm=1&show_dir=both"
SUBMIT_YANG_CATALOG_IMPACT_DESC = "Yang impact analysis for {draft}"
SUBMIT_YANG_CATALOG_MODULE_URL = "https://www.yangcatalog.org/yang-search/module_details.php?module={module}"
SUBMIT_YANG_CATALOG_MODULE_DESC = "Yang catalog entry for {module}"

SUBMIT_YANG_CATALOG_CHECKER_URL = "https://yangcatalog.org/yangvalidator/api/v1/datatracker/{type}"

IDSUBMIT_CHECKER_CLASSES = (
    "ietf.submit.checkers.DraftIdnitsChecker",
    "ietf.submit.checkers.DraftYangChecker",
#    "ietf.submit.checkers.DraftYangvalidatorChecker",    
)

# Max time to allow for validation before a submission is subject to cancellation
IDSUBMIT_MAX_VALIDATION_TIME = datetime.timedelta(minutes=20)

IDSUBMIT_MANUAL_STAGING_DIR = '/tmp/'

IDSUBMIT_FILE_TYPES = (
    'txt',
    'html',
    'xml',
    'pdf',
    'ps',
)
RFC_FILE_TYPES = IDSUBMIT_FILE_TYPES

IDSUBMIT_MAX_DRAFT_SIZE =  {
    'txt':  2*1024*1024,  # Max size of txt draft file in bytes
    'xml':  3*1024*1024,  # Max size of xml draft file in bytes
    'html': 4*1024*1024,
    'pdf':  6*1024*1024,
    'ps' :  6*1024*1024,
}

IDSUBMIT_MAX_DAILY_SAME_DRAFT_NAME = 20
IDSUBMIT_MAX_DAILY_SAME_DRAFT_NAME_SIZE = 50 # in MB
IDSUBMIT_MAX_DAILY_SAME_SUBMITTER = 50
IDSUBMIT_MAX_DAILY_SAME_SUBMITTER_SIZE = 150 # in MB
IDSUBMIT_MAX_DAILY_SAME_GROUP = 150
IDSUBMIT_MAX_DAILY_SAME_GROUP_SIZE = 450 # in MB
IDSUBMIT_MAX_DAILY_SUBMISSIONS = 1000
IDSUBMIT_MAX_DAILY_SUBMISSIONS_SIZE = 2000 # in MB


# === Meeting Related Settings =================================================

MEETING_MATERIALS_SERVE_LOCALLY = True

# If you override MEETING_MATERIALS_SERVE_LOCALLY in your settings_local.conf, you will need to
# set the right value for MEETING_DOC_HREFS there as well. MEETING_DOC_LOCAL_HREFS and 
# CDN_MEETING_DOC_HREFS are defined here to make that simpler.

MEETING_DOC_LOCAL_HREFS = {
    "agenda": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
    "minutes": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
    "slides": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
    "chatlog": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
    "polls": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
    "recording": "{doc.external_url}",
    "bluesheets": "https://www.ietf.org/proceedings/{meeting.number}/bluesheets/{doc.uploaded_filename}",
    "procmaterials": "/meeting/{meeting.number}/materials/{doc.name}-{doc.rev}",
}

MEETING_DOC_CDN_HREFS = {
    "agenda": "https://www.ietf.org/proceedings/{meeting.number}/agenda/{doc.name}-{doc.rev}",
    "minutes": "https://www.ietf.org/proceedings/{meeting.number}/minutes/{doc.name}-{doc.rev}",
    "slides": "https://www.ietf.org/proceedings/{meeting.number}/slides/{doc.name}-{doc.rev}",
    "recording": "{doc.external_url}",
    "bluesheets": "https://www.ietf.org/proceedings/{meeting.number}/bluesheets/{doc.uploaded_filename}",
    "procmaterials": "https://www.ietf.org/proceedings/{meeting.number}/procmaterials/{doc.name}-{doc.rev}",
}

MEETING_DOC_HREFS = MEETING_DOC_LOCAL_HREFS if MEETING_MATERIALS_SERVE_LOCALLY else MEETING_DOC_CDN_HREFS

MEETING_DOC_OLD_HREFS = {
    "agenda": "/meeting/{meeting.number}/materials/{doc.name}",
    "minutes": "/meeting/{meeting.number}/materials/{doc.name}",
    "slides": "/meeting/{meeting.number}/materials/{doc.name}",
    "recording": "{doc.external_url}",
    "bluesheets": "https://www.ietf.org/proceedings/{meeting.number}/bluesheets/{doc.uploaded_filename}",
}

# For http references to documents without a version number (that is, to the current version at the time of reference)
MEETING_DOC_GREFS = {
    "agenda": "/meeting/{meeting.number}/materials/{doc.name}",
    "minutes": "/meeting/{meeting.number}/materials/{doc.name}",
    "slides": "/meeting/{meeting.number}/materials/{doc.name}",
    "recording": "{doc.external_url}",
    "bluesheets": "https://www.ietf.org/proceedings/{meeting.number}/bluesheets/{doc.uploaded_filename}",
    "procmaterials": "/meeting/{meeting.number}/materials/{doc.name}",
}

MEETING_MATERIALS_DEFAULT_SUBMISSION_START_DAYS = 90
MEETING_MATERIALS_DEFAULT_SUBMISSION_CUTOFF_DAYS = 26
MEETING_MATERIALS_DEFAULT_SUBMISSION_CORRECTION_DAYS = 50

MEETING_VALID_UPLOAD_EXTENSIONS = {
    'agenda':       ['.txt','.html','.htm', '.md', ],
    'minutes':      ['.txt','.html','.htm', '.md', '.pdf', ],
    'slides':       ['.doc','.docx','.pdf','.ppt','.pptx','.txt', ], # Note the removal of .zip
    'bluesheets':   ['.pdf', '.txt', ],
    'procmaterials':['.pdf', ],
    'meetinghostlogo':  ['.png', '.jpg', '.jpeg'],
}
    
MEETING_VALID_UPLOAD_MIME_TYPES = {
    'agenda':       ['text/plain', 'text/html', 'text/markdown', 'text/x-markdown', ],
    'minutes':      ['text/plain', 'text/html', 'application/pdf', 'text/markdown', 'text/x-markdown', ],
    'slides':       [],
    'bluesheets':   ['application/pdf', 'text/plain', ],
    'procmaterials':['application/pdf', ],
    'meetinghostlogo':  ['image/jpeg', 'image/png', ],
}

MEETING_VALID_MIME_TYPE_EXTENSIONS = {
    'text/plain':   ['.txt', '.md', ],
    'text/markdown': ['.txt', '.md', ],
    'text/x-markdown': ['.txt', '.md', ],
    'text/html':    ['.html', '.htm'],
    'application/pdf': ['.pdf'],
}

# Files uploaded with Content-Type application/octet-stream and an extension in this map will
# be treated as if they had been uploaded with the mapped Content-Type value.
MEETING_APPLICATION_OCTET_STREAM_OVERRIDES = {
    '.md': 'text/markdown',
}

MEETING_VALID_UPLOAD_MIME_FOR_OBSERVED_MIME = {
    'text/plain':   ['text/plain', 'text/markdown', 'text/x-markdown', ],
    'text/html':    ['text/html', ],
    'application/pdf': ['application/pdf', ],
}

INTERNET_DRAFT_DAYS_TO_EXPIRE = 185

FLOORPLAN_MEDIA_DIR = 'floor'
FLOORPLAN_DIR = os.path.join(MEDIA_ROOT, FLOORPLAN_MEDIA_DIR)

MEETING_LEGACY_OFFICE_HOURS_END = 112  # last meeting to use legacy office hours representation

# Maximum dimensions to accept at all
MEETINGHOST_LOGO_MAX_UPLOAD_WIDTH = 400
MEETINGHOST_LOGO_MAX_UPLOAD_HEIGHT = 400

# Maximum dimensions to display
MEETINGHOST_LOGO_MAX_DISPLAY_WIDTH = 120
MEETINGHOST_LOGO_MAX_DISPLAY_HEIGHT = 120

# Session assignments on the official schedule lock this long before the timeslot starts
MEETING_SESSION_LOCK_TIME = datetime.timedelta(minutes=10)

# === OpenID Connect Provide Related Settings ==================================

# Used by django-oidc-provider
LOGIN_URL = '/accounts/login/'
OIDC_USERINFO = 'ietf.ietfauth.utils.openid_userinfo'
OIDC_EXTRA_SCOPE_CLAIMS = 'ietf.ietfauth.utils.OidcExtraScopeClaims'

# ==============================================================================


RSYNC_BINARY = '/usr/bin/rsync'
YANGLINT_BINARY = '/usr/bin/yanglint'
DE_GFM_BINARY = '/usr/bin/de-gfm.ruby2.5'

# Account settings
DAYS_TO_EXPIRE_REGISTRATION_LINK = 3
MINUTES_TO_EXPIRE_RESET_PASSWORD_LINK = 60
HTPASSWD_COMMAND = "/usr/bin/htpasswd"
HTPASSWD_FILE = "/www/htpasswd"

# Generation of pdf files
GHOSTSCRIPT_COMMAND = "/usr/bin/gs"

# Generation of bibxml files (currently only for internet drafts)
BIBXML_BASE_PATH = '/a/ietfdata/derived/bibxml'

# Timezone files for iCalendar
TZDATA_ICS_PATH = BASE_DIR + '/../vzic/zoneinfo/'

SECR_BLUE_SHEET_PATH = '/a/www/ietf-datatracker/documents/blue_sheet.rtf'
SECR_BLUE_SHEET_URL = IDTRACKER_BASE_URL + '/documents/blue_sheet.rtf'
SECR_INTERIM_LISTING_DIR = '/a/www/www6/meeting/interim'
SECR_MAX_UPLOAD_SIZE = 40960000
SECR_PROCEEDINGS_DIR = '/a/www/www6s/proceedings/'
SECR_PPT2PDF_COMMAND = ['/usr/bin/soffice','--headless','--convert-to','pdf:writer_globaldocument_pdf_Export','--outdir']
STATS_REGISTRATION_ATTENDEES_JSON_URL = 'https://registration.ietf.org/{number}/attendees/'
PROCEEDINGS_VERSION_CHANGES = [
    0,   # version 1
    97,  # version 2: meeting 97 and later (was number was NEW_PROCEEDINGS_START)
    111, # version 3: meeting 111 and later
]
PROCEEDINGS_V1_BASE_URL = 'https://www.ietf.org/proceedings/{meeting.number}'
YOUTUBE_API_KEY = ''
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
YOUTUBE_BASE_URL = 'https://www.youtube.com/watch'
YOUTUBE_IETF_CHANNEL_ID = 'UC8dtK9njBLdFnBahHFp0eZQ'

# If we need to revert to xmpp, change this to 'xmpp:{chat_room_name}@jabber.ietf.org?join'
CHAT_URL_PATTERN = 'https://zulip.ietf.org/#narrow/stream/{chat_room_name}'

# If we need to revert to xmpp
# CHAT_ARCHIVE_URL_PATTERN = 'https://www.ietf.org/jabber/logs/{chat_room_name}?C=M;O=D'

PYFLAKES_DEFAULT_ARGS= ["ietf", ]
VULTURE_DEFAULT_ARGS= ["ietf", ]

# Automatic Scheduling
#
# how much to login while running, bigger numbers make it more verbose.
BADNESS_CALC_LOG   = 0
#
# these penalties affect the calculation of how bad the assignments are.
BADNESS_UNPLACED   = 1000000

# following four are used only during migrations to setup up ConstraintName
# and penalties are taken from the database afterwards.
BADNESS_BETHERE    = 200000
BADNESS_CONFLICT_1 = 100000
BADNESS_CONFLICT_2 = 10000
BADNESS_CONFLICT_3 = 1000

BADNESS_TOOSMALL_50  = 5000
BADNESS_TOOSMALL_100 = 50000
BADNESS_TOOBIG     = 100
BADNESS_MUCHTOOBIG = 500

# Set debug apps in settings_local.DEV_APPS

DEV_APPS = []                           # type: List[str]
DEV_PRE_APPS = []                       # type: List[str]
DEV_MIDDLEWARE = ()

PROD_PRE_APPS = []                      # type: List[str]

# django-debug-toolbar and the debug listing of sql queries at the bottom of
# each page when in dev mode can overlap in functionality, and can slow down
# page loading.  If you wish to use the sql_queries debug listing, put this in
# your settings_local and make sure your client IP address is in INTERNAL_IPS:
#
#    DEV_TEMPLATE_CONTEXT_PROCESSORS = [
#        'ietf.context_processors.sql_debug',
#    ]
#
DEV_TEMPLATE_CONTEXT_PROCESSORS = []    # type: List[str]

# Domain which hosts draft and wg alias lists
DRAFT_ALIAS_DOMAIN = IETF_DOMAIN
GROUP_ALIAS_DOMAIN = IETF_DOMAIN

TEST_DATA_DIR = os.path.abspath(BASE_DIR + "/../test/data")

# Path to the email alias lists.  Used by ietf.utils.aliases
DRAFT_ALIASES_PATH = os.path.join(TEST_DATA_DIR, "draft-aliases")
DRAFT_VIRTUAL_PATH = os.path.join(TEST_DATA_DIR, "draft-virtual")
DRAFT_VIRTUAL_DOMAIN = "virtual.ietf.org"

GROUP_ALIASES_PATH = os.path.join(TEST_DATA_DIR, "group-aliases")
GROUP_VIRTUAL_PATH = os.path.join(TEST_DATA_DIR, "group-virtual")
GROUP_VIRTUAL_DOMAIN = "virtual.ietf.org"

POSTCONFIRM_PATH   = "/a/postconfirm/wrapper"

USER_PREFERENCE_DEFAULTS = {
    "expires_soon"  : "14",
    "new_enough"    : "14",
    "full_draft"    : "on",
    "left_menu"     : "off",
}


# Email addresses people attempt to set for their account will be checked
# against the following list of regex expressions with re.search(pat, addr):
EXCLUDED_PERSONAL_EMAIL_REGEX_PATTERNS = [
    "@ietf.org$",
]

MARKUP_SETTINGS = {
    'restructuredtext': {
        'settings_overrides': {
            'initial_header_level': 3,
            'doctitle_xform': False,
            'footnote_references': 'superscript',
            'trim_footnote_reference_space': True,
            'default_reference_context': 'view',
            'link_base': ''
        }
    }
}

MAILMAN_LIB_DIR = '/usr/lib/mailman'

# This is the number of seconds required between subscribing to an ietf
# mailing list and datatracker account creation being accepted
LIST_ACCOUNT_DELAY = 60*60*25           # 25 hours
ACCOUNT_REQUEST_EMAIL = 'account-request@ietf.org'


SILENCED_SYSTEM_CHECKS = [
    "fields.W342",  # Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.
]

CHECKS_LIBRARY_PATCHES_TO_APPLY = [
    'patch/change-oidc-provider-field-sizes-228.patch',
    'patch/fix-oidc-access-token-post.patch',
    'patch/fix-jwkest-jwt-logging.patch',
    'patch/fix-django-password-strength-kwargs.patch',
    'patch/add-django-http-cookie-value-none.patch',
    'patch/django-cookie-delete-with-all-settings.patch',
    'patch/tastypie-django22-fielderror-response.patch',
]
if DEBUG:
    try:
        import django_cprofile_middleware # pyflakes:ignore
        CHECKS_LIBRARY_PATCHES_TO_APPLY += [ 'patch/add-django-cprofile-filter.patch', ]
    except ImportError:
        pass

STATS_NAMES_LIMIT = 25

UTILS_MEETING_CONFERENCE_DOMAINS = ['webex.com', 'zoom.us', 'jitsi.org', 'meetecho.com', 'gather.town', ]
UTILS_TEST_RANDOM_STATE_FILE = '.factoryboy_random_state'
UTILS_APIKEY_GUI_LOGIN_LIMIT_DAYS = 30


API_KEY_TYPE="ES256"                    # EC / P=256
API_PUBLIC_KEY_PEM = b"""
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqVojsaofDJScuMJN+tshumyNM5ME
garzVPqkVovmF6yE7IJ/dv4FcV+QKCtJ/rOS8e36Y8ZAEVYuukhes0yZ1w==
-----END PUBLIC KEY-----
"""
API_PRIVATE_KEY_PEM = b"""
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoI6LJkopKq8XrHi9
QqGQvE4A83TFYjqLz+8gULYecsqhRANCAASpWiOxqh8MlJy4wk362yG6bI0zkwSB
qvNU+qRWi+YXrITsgn92/gVxX5AoK0n+s5Lx7fpjxkARVi66SF6zTJnX
-----END PRIVATE KEY-----
"""


# Default timeout for HTTP requests via the requests library
DEFAULT_REQUESTS_TIMEOUT = 20  # seconds


# Celery configuration
CELERY_TIMEZONE = 'UTC'
CELERY_BROKER_URL = 'amqp://mq/'
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
CELERY_BEAT_SYNC_EVERY = 1  # update DB after every event

# Meetecho API setup: Uncomment this and provide real credentials to enable
# Meetecho conference creation for interim session requests
#
# MEETECHO_API_CONFIG = {
#     'api_base': 'https://meetings.conf.meetecho.com/api/v1/',
#     'client_id': 'datatracker',
#     'client_secret': 'some secret',
#     'request_timeout': 3.01,  # python-requests doc recommend slightly > a multiple of 3 seconds
# }


# Put the production SECRET_KEY in settings_local.py, and also any other
# sensitive or site-specific changes.  DO NOT commit settings_local.py to svn.
from ietf.settings_local import *            # pyflakes:ignore pylint: disable=wildcard-import

for app in INSTALLED_APPS:
    if app.startswith('ietf'):
        app_settings_file = os.path.join(BASE_DIR, '../', app.replace('.', os.sep), "settings.py")
        if os.path.exists(app_settings_file):
            exec("from %s import *" % (app+".settings"))

# Add APPS from settings_local to INSTALLED_APPS
if SERVER_MODE == 'production':
    INSTALLED_APPS = PROD_PRE_APPS + INSTALLED_APPS
else:
    INSTALLED_APPS += DEV_APPS
    INSTALLED_APPS = DEV_PRE_APPS + INSTALLED_APPS
    MIDDLEWARE += DEV_MIDDLEWARE
    TEMPLATES[0]['OPTIONS']['context_processors'] += DEV_TEMPLATE_CONTEXT_PROCESSORS


# We provide a secret key only for test and development modes.  It's
# absolutely vital that django fails to start in production mode unless a
# secret key has been provided elsewhere, not in this file which is
# publicly available, for instance from the source repository.
if SERVER_MODE != 'production':
    # stomp out the cached template loader, it's annoying
    loaders = TEMPLATES[0]['OPTIONS']['loaders']
    loaders = tuple(l for e in loaders for l in (e[1] if isinstance(e, tuple) and "cached.Loader" in e[0] else (e,)))
    TEMPLATES[0]['OPTIONS']['loaders'] = loaders

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
            #'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            #'LOCATION': '127.0.0.1:11211',
            #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
            'VERSION': __version__,
            'KEY_PREFIX': 'ietf:dt',
        },
        'sessions': {
            'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        },
        'htmlized': {
            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
            #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
            'LOCATION': '/var/cache/datatracker/htmlized',
            'OPTIONS': {
                'MAX_ENTRIES': 1000,
            },
        },
        'pdfized': {
            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
            #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
            'LOCATION': '/var/cache/datatracker/pdfized',
            'OPTIONS': {
                'MAX_ENTRIES': 1000,
            },
        },
        'slowpages': {
            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
            #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
            'LOCATION': '/var/cache/datatracker/',
            'OPTIONS': {
                'MAX_ENTRIES': 5000,
            },
        },
    }
    SESSION_ENGINE = "django.contrib.sessions.backends.db"

    if 'SECRET_KEY' not in locals():
        SECRET_KEY = 'PDwXboUq!=hPjnrtG2=ge#N$Dwy+wn@uivrugwpic8mxyPfHka'
    if 'NOMCOM_APP_SECRET' not in locals():
        NOMCOM_APP_SECRET = b'\x9b\xdas1\xec\xd5\xa0SI~\xcb\xd4\xf5t\x99\xc4i\xd7\x9f\x0b\xa9\xe8\xfeY\x80$\x1e\x12tN:\x84'

    ALLOWED_HOSTS = ['*',]
    
    try:
        # see https://github.com/omarish/django-cprofile-middleware
        import django_cprofile_middleware # pyflakes:ignore
        MIDDLEWARE = MIDDLEWARE + ['django_cprofile_middleware.middleware.ProfilerMiddleware', ]
    except ImportError:
        pass

    # Cannot have this set to True if we're using http: from the dev-server:
    CSRF_COOKIE_SECURE = False
    CSRF_COOKIE_SAMESITE = 'Lax'
    SESSION_COOKIE_SECURE = False
    SESSION_COOKIE_SAMESITE = 'Lax'