Settings and public domain restructure (#1829)

This performs some needed changes for readthedocs.com as well as for making the .org have knowledge of a secondary hosting domain:

Move settings to class based settings, it's far easier to manage with nested settings
Try to serve all docs (private or public) from the PUBLIC_DOMAIN, if it is set.
Remove old settings files that aren't used. Postgres settings were mostly our old production settings, that file shouldn't exist anymore. onebox.py was never used, and sqlite.py is basically just dev.py. For local postgres development, override DATABASES in local_settings.py, which should already be the case.
Settings for additional URL confs were added for override
break-out-core-urls-views
Anthony 2016-04-14 14:58:28 -07:00
parent d17b50433b
commit b749c5022f
23 changed files with 679 additions and 743 deletions

View File

@ -3,7 +3,7 @@ import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "readthedocs.settings.sqlite")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "readthedocs.settings.dev")
sys.path.append(os.getcwd())
from django.core.management import execute_from_command_line

View File

@ -46,7 +46,6 @@ class ProjectResource(ModelResource, SearchMixin):
return super(ProjectResource, self).get_object_list(request)
def dehydrate(self, bundle):
bundle.data['subdomain'] = "http://%s/" % bundle.obj.subdomain
bundle.data['downloads'] = bundle.obj.get_downloads()
return bundle
@ -130,13 +129,6 @@ class VersionResource(ModelResource):
"active": ALL,
}
# Find a better name for this before including it.
# def dehydrate(self, bundle):
# bundle.data['subdomain'] = "http://%s/en/%s/" % (
# bundle.obj.project.subdomain, bundle.obj.slug
# )
# return bundle
def get_object_list(self, request):
self._meta.queryset = Version.objects.api(user=request.user)
return super(VersionResource, self).get_object_list(request)

View File

@ -182,7 +182,9 @@ class Version(models.Model):
def get_subdomain_url(self):
private = self.privacy_level == PRIVATE
return resolve(project=self.project, version_slug=self.slug, private=private)
return self.project.get_docs_url(version_slug=self.slug,
lang_slug=self.project.language,
private=private)
def get_downloads(self, pretty=False):
project = self.project

View File

@ -12,52 +12,72 @@ from readthedocs.projects.models import Project, Domain
log = logging.getLogger(__name__)
LOG_TEMPLATE = u"(Middleware) {msg} [{host}{path}]"
SUBDOMAIN_URLCONF = getattr(
settings,
'SUBDOMAIN_URLCONF',
'readthedocs.core.subdomain_urls'
)
SINGLE_VERSION_URLCONF = getattr(
settings,
'SINGLE_VERSION_URLCONF',
'readthedocs.core.single_version_urls'
)
class SubdomainMiddleware(object):
def process_request(self, request):
if not getattr(settings, 'USE_SUBDOMAIN', False):
return None
host = request.get_host().lower()
path = request.get_full_path()
log_kwargs = dict(host=host, path=path)
if settings.DEBUG:
log.debug(LOG_TEMPLATE.format(msg='DEBUG on, not processing middleware', **log_kwargs))
return None
public_domain = getattr(settings, 'PUBLIC_DOMAIN', None)
production_domain = getattr(settings, 'PRODUCTION_DOMAIN',
'readthedocs.org')
if public_domain is None:
public_domain = production_domain
if ':' in host:
host = host.split(':')[0]
domain_parts = host.split('.')
# Serve subdomains - but don't depend on the production domain only having 2 parts
if len(domain_parts) == len(settings.PRODUCTION_DOMAIN.split('.')) + 1:
if len(domain_parts) == len(public_domain.split('.')) + 1:
subdomain = domain_parts[0]
is_www = subdomain.lower() == 'www'
is_ssl = subdomain.lower() == 'ssl'
if not is_www and not is_ssl and settings.PRODUCTION_DOMAIN in host:
if not is_www and not is_ssl and public_domain in host:
request.subdomain = True
request.slug = subdomain
request.urlconf = 'readthedocs.core.subdomain_urls'
request.urlconf = SUBDOMAIN_URLCONF
return None
# Serve CNAMEs
if settings.PRODUCTION_DOMAIN not in host and \
'localhost' not in host and \
'testserver' not in host:
if (public_domain not in host and
production_domain not in host and
'localhost' not in host and
'testserver' not in host):
request.cname = True
domains = Domain.objects.filter(domain=host)
if domains.count():
for domain in domains:
if domain.domain == host:
request.slug = domain.project.slug
request.urlconf = 'core.subdomain_urls'
request.urlconf = SUBDOMAIN_URLCONF
request.domain_object = True
log.debug(LOG_TEMPLATE.format(
msg='Domain Object Detected: %s' % domain.domain, **log_kwargs))
msg='Domain Object Detected: %s' % domain.domain,
**log_kwargs))
break
if not hasattr(request, 'domain_object') and 'HTTP_X_RTD_SLUG' in request.META:
if (not hasattr(request, 'domain_object') and
'HTTP_X_RTD_SLUG' in request.META):
request.slug = request.META['HTTP_X_RTD_SLUG'].lower()
request.urlconf = 'readthedocs.core.subdomain_urls'
request.urlconf = SUBDOMAIN_URLCONF
request.rtdheader = True
log.debug(LOG_TEMPLATE.format(
msg='X-RTD-Slug header detetected: %s' % request.slug, **log_kwargs))
msg='X-RTD-Slug header detetected: %s' % request.slug,
**log_kwargs))
# Try header first, then DNS
elif not hasattr(request, 'domain_object'):
try:
@ -73,7 +93,7 @@ class SubdomainMiddleware(object):
msg='CNAME cached: %s->%s' % (slug, host),
**log_kwargs))
request.slug = slug
request.urlconf = 'readthedocs.core.subdomain_urls'
request.urlconf = SUBDOMAIN_URLCONF
log.debug(LOG_TEMPLATE.format(
msg='CNAME detetected: %s' % request.slug,
**log_kwargs))
@ -134,9 +154,8 @@ class SingleVersionMiddleware(object):
# Let 404 be handled further up stack.
return None
if (getattr(proj, 'single_version', False) and
not getattr(settings, 'USE_SUBDOMAIN', False)):
request.urlconf = 'readthedocs.core.single_version_urls'
if getattr(proj, 'single_version', False):
request.urlconf = SINGLE_VERSION_URLCONF
# Logging
host = request.get_host()
path = request.get_full_path()

View File

@ -29,9 +29,10 @@ All possible URL's::
/docs/<project_slug>/projects/<subproject_slug>/<filename> # Subproject Single Version
"""
from django.conf import settings
import re
from django.conf import settings
from readthedocs.projects.constants import PRIVATE, PUBLIC
@ -68,13 +69,14 @@ def _fix_filename(project, filename):
return path
def base_resolve_path(project_slug, filename, version_slug=None, language=None, private=False,
single_version=None, subproject_slug=None, subdomain=None, cname=None):
""" Resolve a with nothing smart, just filling in the blanks."""
if private:
url = '/docs/{project_slug}/'
elif subdomain or cname:
def base_resolve_path(project_slug, filename, version_slug=None, language=None,
private=False, single_version=None, subproject_slug=None,
subdomain=None, cname=None):
"""Resolve a with nothing smart, just filling in the blanks"""
# Only support `/docs/project' URLs outside our normal environment. Normally
# the path should always have a subdomain or CNAME domain
use_subdomain = getattr(settings, 'USE_SUBDOMAIN', False)
if subdomain or cname or (private and use_subdomain):
url = '/'
else:
url = '/docs/{project_slug}/'
@ -154,9 +156,7 @@ def resolve_domain(project, private=None):
domain = canonical_project.domains.filter(canonical=True).first()
# Force domain even if USE_SUBDOMAIN is on
if private:
return prod_domain
elif domain:
if domain:
return domain.domain
elif subdomain:
subdomain_slug = canonical_project.slug.replace('_', '-')

View File

@ -0,0 +1,25 @@
"""Class based settings for complex settings inheritance"""
import inspect
import sys
class Settings(object):
"""Class-based settings wrapper"""
@classmethod
def load_settings(cls, module_name):
"""Export class variables and properties to module namespace
This will export and class variable that is all upper case and doesn't
begin with ``_``. These members will be set as attributes on the module
``module_name``.
"""
self = cls()
module = sys.modules[module_name]
for (member, value) in inspect.getmembers(self):
if member.isupper() and not member.startswith('_'):
if isinstance(value, property):
value = value.fget(self)
setattr(module, member, value)

View File

@ -60,8 +60,9 @@ from collections import OrderedDict
from django.conf import settings
from readthedocs.builds.models import Version
from readthedocs.projects import constants
from readthedocs.projects.models import Domain, Project
from readthedocs.projects.models import Domain
from readthedocs.projects.utils import run
log = logging.getLogger(__name__)
@ -241,20 +242,19 @@ class Symlink(object):
Link from $WEB_ROOT/<project> ->
HOME/user_builds/<project>/rtd-builds/latest/
"""
default_version = self.get_default_version()
if default_version is None:
return
self._log("Symlinking single_version")
version = self.get_default_version()
# Clean up symlinks
symlink = self.project_root
if os.path.islink(symlink):
os.unlink(symlink)
if os.path.exists(symlink):
shutil.rmtree(symlink)
# Where the actual docs live
docs_dir = os.path.join(settings.DOCROOT, self.project.slug, 'rtd-builds', default_version)
# Create symlink
if version is not None:
docs_dir = os.path.join(settings.DOCROOT, self.project.slug,
'rtd-builds', version.slug)
run('ln -nsf %s/ %s' % (docs_dir, symlink))
def symlink_versions(self):
@ -284,6 +284,14 @@ class Symlink(object):
if old_ver not in versions:
os.unlink(os.path.join(version_dir, old_ver))
def get_default_version(self):
"""Look up project default version, return None if not found"""
default_version = self.project.get_default_version()
try:
return self.get_version_queryset().get(slug=default_version)
except Version.DoesNotExist:
return None
class PublicSymlink(Symlink):
CNAME_ROOT = os.path.join(settings.SITE_ROOT, 'public_cname_root')
@ -300,12 +308,6 @@ class PublicSymlink(Symlink):
def get_translations(self):
return self.project.translations.protected()
def get_default_version(self):
default_version = self.project.get_default_version()
if self.project.versions.protected().filter(slug=default_version).exists():
return default_version
return None
def run_sanity_check(self):
return self.project.privacy_level in [constants.PUBLIC, constants.PROTECTED]
@ -327,10 +329,3 @@ class PrivateSymlink(Symlink):
def get_translations(self):
return self.project.translations.private()
def get_default_version(self):
default_version = self.project.get_default_version()
version_qs = self.project.versions.private().filter(slug=default_version)
if version_qs.exists():
return default_version
return None

View File

@ -105,7 +105,8 @@ class BaseMkdocs(BaseBuilder):
'builder': "mkdocs",
'docroot': docs_dir,
'source_suffix': ".md",
'api_host': getattr(settings, 'SLUMBER_API_HOST', 'https://readthedocs.org'),
'api_host': getattr(settings, 'PUBLIC_API_URL',
'https://readthedocs.org'),
'commit': self.version.project.vcs_repo(self.version.slug).commit,
}
data_json = json.dumps(readthedocs_data, indent=4)

View File

@ -97,7 +97,8 @@ class BaseSphinx(BaseBuilder):
'static_path': SPHINX_STATIC_DIR,
'template_path': SPHINX_TEMPLATE_DIR,
'conf_py_path': conf_py_path,
'api_host': getattr(settings, 'SLUMBER_API_HOST', 'https://readthedocs.org'),
'api_host': getattr(settings, 'PUBLIC_API_URL',
'https://readthedocs.org'),
# GitHub
'github_user': github_user,
'github_repo': github_repo,

View File

@ -28,7 +28,7 @@ from readthedocs.projects.templatetags.projects_tags import sort_version_aware
from readthedocs.projects.utils import make_api_version, update_static_metadata
from readthedocs.projects.version_handling import determine_stable_version
from readthedocs.projects.version_handling import version_windows
from readthedocs.core.resolver import resolve
from readthedocs.core.resolver import resolve, resolve_domain
from readthedocs.core.validators import validate_domain_name
from readthedocs.vcs_support.base import VCSProject
@ -290,16 +290,6 @@ class Project(models.Model):
def __unicode__(self):
return self.name
@property
def subdomain(self):
try:
domain = self.domains.get(canonical=True)
return domain.domain
except (Domain.DoesNotExist, MultipleObjectsReturned):
subdomain_slug = self.slug.replace('_', '-')
prod_domain = getattr(settings, 'PRODUCTION_DOMAIN')
return "%s.%s" % (subdomain_slug, prod_domain)
def sync_supported_versions(self):
supported = self.supported_versions()
if supported:
@ -421,6 +411,10 @@ class Project(models.Model):
path = '//%s%s' % (settings.PRODUCTION_DOMAIN, path)
return path
def subdomain(self):
"""Get project subdomain from resolver"""
return resolve_domain(self)
def get_downloads(self):
downloads = {}
downloads['htmlzip'] = self.get_production_media_url(

View File

@ -52,7 +52,6 @@ def mock_version(repo):
"requirements_file": "",
"resource_uri": "/api/v1/project/2599/",
"slug": "docs",
"subdomain": "http://docs.readthedocs.org/",
"suffix": ".rst",
"theme": "default",
"install_project": false,

View File

@ -21,6 +21,7 @@ def create_user(username, password):
return user
@override_settings(USE_SUBDOMAIN=True)
class MiddlewareTests(TestCase):
def setUp(self):
@ -57,7 +58,7 @@ class MiddlewareTests(TestCase):
request = self.factory.get(self.url, HTTP_HOST='docs.foobar.com')
self.middleware.process_request(request)
self.assertEqual(request.urlconf, 'core.subdomain_urls')
self.assertEqual(request.urlconf, 'readthedocs.core.subdomain_urls')
self.assertEqual(request.domain_object, True)
self.assertEqual(request.slug, 'pip')
@ -100,8 +101,8 @@ class MiddlewareTests(TestCase):
self.assertEqual(request.rtdheader, True)
self.assertEqual(request.slug, 'pip')
@override_settings(DEBUG=True)
def test_debug_on(self):
@override_settings(USE_SUBDOMAIN=True)
def test_use_subdomain_on(self):
request = self.factory.get(self.url, HTTP_HOST='doesnt.really.matter')
ret_val = self.middleware.process_request(request)
self.assertEqual(ret_val, None)

View File

@ -255,6 +255,16 @@ class TestPublicSymlinkSingleVersion(TestCase):
for index, command in enumerate(commands):
self.assertEqual(self.commands[index], command.format(**self.args))
@patched
def test_symlink_single_version_missing(self):
project = get(Project)
project.versions.update(privacy_level='private')
symlink = PublicSymlink(project)
# Set because *something* triggers project symlinking on get(Project)
self.commands = []
symlink.symlink_single_version()
self.assertEqual([], self.commands)
class BaseSymlinkVersions(object):

View File

@ -120,28 +120,33 @@ class RedirectTests(TestCase):
self.assertEqual(r.status_code, 404)
# Subdomains
@override_settings(USE_SUBDOMAIN=True)
def test_proper_subdomain(self):
r = self.client.get('/', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 302)
self.assertEqual(
r['Location'], 'http://pip.readthedocs.org/en/latest/')
@override_settings(USE_SUBDOMAIN=True)
def test_proper_subdomain_with_lang_slug_only(self):
r = self.client.get('/en/', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 302)
self.assertEqual(
r['Location'], 'http://pip.readthedocs.org/en/latest/')
@override_settings(USE_SUBDOMAIN=True)
def test_proper_subdomain_and_url(self):
r = self.client.get('/en/latest/', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 200)
@override_settings(USE_SUBDOMAIN=True)
def test_proper_subdomain_and_url_with_filename(self):
r = self.client.get(
'/en/latest/test.html', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 200)
# Specific Page Redirects
@override_settings(USE_SUBDOMAIN=True)
def test_proper_page_on_subdomain(self):
r = self.client.get('/page/test.html', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 302)
@ -149,12 +154,14 @@ class RedirectTests(TestCase):
'http://pip.readthedocs.org/en/latest/test.html')
# When there's only a version slug, the redirect prepends the lang slug
@override_settings(USE_SUBDOMAIN=True)
def test_proper_subdomain_with_version_slug_only(self):
r = self.client.get('/1.4.1/', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 302)
self.assertEqual(r['Location'],
'http://pip.readthedocs.org/en/1.4.1/')
@override_settings(USE_SUBDOMAIN=True)
def test_improper_subdomain_filename_only(self):
r = self.client.get('/test.html', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 404)
@ -170,6 +177,7 @@ class RedirectUnderscoreTests(TestCase):
slug='what_up', name='What Up Underscore')
# Test _ -> - slug lookup
@override_settings(USE_SUBDOMAIN=True)
def test_underscore_redirect(self):
r = self.client.get('/',
HTTP_HOST='what-up.readthedocs.org')

View File

@ -246,10 +246,10 @@ class ResolverDomainTests(ResolverBase):
# Private overrides domain
with override_settings(USE_SUBDOMAIN=False):
url = resolve_domain(project=self.translation, private=True)
self.assertEqual(url, 'readthedocs.org')
self.assertEqual(url, 'public.readthedocs.org')
with override_settings(USE_SUBDOMAIN=True):
url = resolve_domain(project=self.translation, private=True)
self.assertEqual(url, 'readthedocs.org')
self.assertEqual(url, 'pip.public.readthedocs.org')
class ResolverTests(ResolverBase):
@ -320,7 +320,7 @@ class ResolverTests(ResolverBase):
self.assertEqual(url, 'http://readthedocs.org/docs/pip/en/latest/')
with override_settings(USE_SUBDOMAIN=True):
url = resolve(project=self.pip, private=True)
self.assertEqual(url, 'http://readthedocs.org/docs/pip/en/latest/')
self.assertEqual(url, 'http://pip.readthedocs.org/en/latest/')
@override_settings(PRODUCTION_DOMAIN='readthedocs.org')
def test_resolver_private_project_override(self):
@ -348,7 +348,7 @@ class ResolverTests(ResolverBase):
self.assertEqual(url, 'http://readthedocs.org/docs/pip/en/latest/')
with override_settings(USE_SUBDOMAIN=True):
url = resolve(project=self.pip)
self.assertEqual(url, 'http://readthedocs.org/docs/pip/en/latest/')
self.assertEqual(url, 'http://pip.readthedocs.org/en/latest/')
url = resolve(project=self.pip, private=False)
self.assertEqual(url, 'http://pip.readthedocs.org/en/latest/')
@ -356,12 +356,12 @@ class ResolverTests(ResolverBase):
def test_resolver_public_domain_overrides(self):
with override_settings(USE_SUBDOMAIN=False):
url = resolve(project=self.pip, private=True)
self.assertEqual(url, 'http://readthedocs.org/docs/pip/en/latest/')
self.assertEqual(url, 'http://public.readthedocs.org/docs/pip/en/latest/')
url = resolve(project=self.pip, private=False)
self.assertEqual(url, 'http://public.readthedocs.org/docs/pip/en/latest/')
with override_settings(USE_SUBDOMAIN=True):
url = resolve(project=self.pip, private=True)
self.assertEqual(url, 'http://readthedocs.org/docs/pip/en/latest/')
self.assertEqual(url, 'http://pip.public.readthedocs.org/en/latest/')
url = resolve(project=self.pip, private=False)
self.assertEqual(url, 'http://pip.public.readthedocs.org/en/latest/')
@ -369,11 +369,11 @@ class ResolverTests(ResolverBase):
self.domain = get(Domain, domain='docs.foobar.com', project=self.pip, canonical=True)
with override_settings(USE_SUBDOMAIN=True):
url = resolve(project=self.pip, private=True)
self.assertEqual(url, 'http://readthedocs.org/docs/pip/en/latest/')
self.assertEqual(url, 'http://docs.foobar.com/en/latest/')
url = resolve(project=self.pip, private=False)
self.assertEqual(url, 'http://docs.foobar.com/en/latest/')
with override_settings(USE_SUBDOMAIN=False):
url = resolve(project=self.pip, private=True)
self.assertEqual(url, 'http://readthedocs.org/docs/pip/en/latest/')
self.assertEqual(url, 'http://docs.foobar.com/en/latest/')
url = resolve(project=self.pip, private=False)
self.assertEqual(url, 'http://docs.foobar.com/en/latest/')

View File

@ -1,10 +1,12 @@
from django.test import TestCase
from django.test.utils import override_settings
from readthedocs.builds.constants import LATEST
from readthedocs.builds.models import Version
from readthedocs.projects.models import Project
@override_settings(USE_SUBDOMAIN=True, PUBLIC_DOMAIN='public.readthedocs.org')
class RedirectSingleVersionTests(TestCase):
fixtures = ["eric", "test_data"]
@ -20,32 +22,38 @@ class RedirectSingleVersionTests(TestCase):
self.assertTrue(Version.objects.filter(project__name__exact='Pip').get(slug=LATEST))
def test_proper_single_version_url_full_with_filename(self):
with override_settings(USE_SUBDOMAIN=False):
r = self.client.get('/docs/pip/usage.html')
self.assertEqual(r.status_code, 200)
def test_improper_single_version_url_nonexistent_project(self):
with override_settings(USE_SUBDOMAIN=False):
r = self.client.get('/docs/nonexistent/blah.html')
self.assertEqual(r.status_code, 404)
def test_proper_single_version_url_subdomain(self):
r = self.client.get('/usage.html', HTTP_HOST='pip.readthedocs.org')
r = self.client.get('/usage.html',
HTTP_HOST='pip.public.readthedocs.org')
self.assertEqual(r.status_code, 200)
def test_improper_single_version_url_subdomain(self):
r = self.client.get('/blah.html', HTTP_HOST='nonexistent.readthedocs.org')
r = self.client.get('/blah.html',
HTTP_HOST='nonexistent.public.readthedocs.org')
self.assertEqual(r.status_code, 404)
def test_docs_url_generation(self):
self.pip.single_version = True
with self.settings(USE_SUBDOMAIN=False):
self.assertEqual(self.pip.get_docs_url(), 'http://readthedocs.org/docs/pip/')
with self.settings(USE_SUBDOMAIN=True):
self.assertEqual(self.pip.get_docs_url(), 'http://pip.readthedocs.org/')
with override_settings(USE_SUBDOMAIN=False):
self.assertEqual(self.pip.get_docs_url(),
'http://public.readthedocs.org/docs/pip/')
with override_settings(USE_SUBDOMAIN=True):
self.assertEqual(self.pip.get_docs_url(),
'http://pip.public.readthedocs.org/')
self.pip.single_version = False
with self.settings(USE_SUBDOMAIN=False):
self.assertEqual(self.pip.get_docs_url(), 'http://readthedocs.org/docs/pip/en/latest/')
with self.settings(USE_SUBDOMAIN=True):
self.assertEqual(self.pip.get_docs_url(), 'http://pip.readthedocs.org/en/latest/')
with override_settings(USE_SUBDOMAIN=False):
self.assertEqual(self.pip.get_docs_url(),
'http://public.readthedocs.org/docs/pip/en/latest/')
with override_settings(USE_SUBDOMAIN=True):
self.assertEqual(self.pip.get_docs_url(),
'http://pip.public.readthedocs.org/en/latest/')

View File

@ -1,175 +1,62 @@
# encoding: utf-8
# pylint: disable=missing-docstring
import os
import djcelery
from kombu.common import Broadcast
from kombu import Exchange, Queue
from readthedocs.core.settings import Settings
djcelery.setup_loader()
_ = gettext = lambda s: s
DEBUG = True
TEMPLATE_DEBUG = DEBUG
TASTYPIE_FULL_DEBUG = True
LOG_DEBUG = False
PRODUCTION_DOMAIN = 'readthedocs.org'
USE_SUBDOMAIN = False
class CommunityBaseSettings(Settings):
ADMINS = (
"""Community base settings, don't use this directly"""
# Django settings
SITE_ID = 1
ROOT_URLCONF = 'readthedocs.urls'
SUBDOMAIN_URLCONF = 'readthedocs.core.subdomain_urls'
LOGIN_REDIRECT_URL = '/dashboard/'
FORCE_WWW = False
SECRET_KEY = 'replace-this-please' # noqa
ATOMIC_REQUESTS = True
# Debug settings
DEBUG = True
TEMPLATE_DEBUG = DEBUG
TASTYPIE_FULL_DEBUG = True
LOG_DEBUG = False
# Domains and URLs
PRODUCTION_DOMAIN = 'readthedocs.org'
PUBLIC_DOMAIN = None
USE_SUBDOMAIN = False
PUBLIC_API_URL = 'https://{0}'.format(PRODUCTION_DOMAIN)
ADMINS = (
('Eric Holscher', 'eric@readthedocs.org'),
('Anthony Johnson', 'anthony@readthedocs.org'),
)
)
MANAGERS = ADMINS
MANAGERS = ADMINS
# Email
DEFAULT_FROM_EMAIL = "no-reply@readthedocs.org"
SERVER_EMAIL = DEFAULT_FROM_EMAIL
SITE_ROOT = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
TEMPLATE_ROOT = os.path.join(SITE_ROOT, 'readthedocs', 'templates')
DOCROOT = os.path.join(SITE_ROOT, 'user_builds')
UPLOAD_ROOT = os.path.join(SITE_ROOT, 'user_uploads')
CNAME_ROOT = os.path.join(SITE_ROOT, 'cnames')
LOGS_ROOT = os.path.join(SITE_ROOT, 'logs')
# Cookies
SESSION_COOKIE_DOMAIN = 'readthedocs.org'
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
# A new base for production files
PRODUCTION_ROOT = os.path.join(SITE_ROOT, 'prod_artifacts')
PRODUCTION_MEDIA_ARTIFACTS = os.path.join(PRODUCTION_ROOT, 'media')
MEDIA_ROOT = '%s/media/' % (SITE_ROOT)
MEDIA_URL = '/media/'
ADMIN_MEDIA_PREFIX = '/media/admin/'
GROK_API_HOST = 'https://api.grokthedocs.com'
SILENCED_SYSTEM_CHECKS = ['fields.W342']
# For 1.4
STATIC_ROOT = os.path.join(SITE_ROOT, 'media/static/')
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(SITE_ROOT, 'readthedocs', 'static')]
# STATICFILES_FINDERS = ()
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'PREFIX': 'docs',
}
}
CACHE_MIDDLEWARE_SECONDS = 60
LOGIN_REDIRECT_URL = '/dashboard/'
FORCE_WWW = False
# APPEND_SLASH = False
# Docker
DOCKER_ENABLE = False
DOCKER_IMAGE = 'rtfd-build'
TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
LANGUAGES = (
('en', gettext('English')),
('es', gettext('Spanish')),
('nb', gettext('Norwegian Bokmål')),
('fr', gettext('French')),
('ru', gettext('Russian')),
('de', gettext('German')),
('gl', gettext('Galician')),
('vi', gettext('Vietnamese')),
('zh-cn', gettext('Chinese')),
('zh-tw', gettext('Taiwanese')),
('ja', gettext('Japanese')),
('uk', gettext('Ukrainian')),
('it', gettext('Italian')),
)
LOCALE_PATHS = [
os.path.join(SITE_ROOT, 'readthedocs', 'locale'),
]
USE_I18N = True
USE_L10N = True
SITE_ID = 1
SECRET_KEY = 'replace-this-please' # noqa: ignore dodgy check
ATOMIC_REQUESTS = True
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
MIDDLEWARE_CLASSES = (
'readthedocs.core.middleware.ProxyMiddleware',
'readthedocs.core.middleware.FooterNoSessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'djangosecure.middleware.SecurityMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'pagination.middleware.PaginationMiddleware',
# Hack
# 'core.underscore_middleware.UnderscoreMiddleware',
'readthedocs.core.middleware.SubdomainMiddleware',
'readthedocs.core.middleware.SingleVersionMiddleware',
'corsheaders.middleware.CorsMiddleware',
# 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)
AUTHENTICATION_BACKENDS = (
# Needed to login by username in Django admin, regardless of `allauth`
"django.contrib.auth.backends.ModelBackend",
# `allauth` specific authentication methods, such as login by e-mail
"allauth.account.auth_backends.AuthenticationBackend",
)
# All auth
ACCOUNT_ACTIVATION_DAYS = 7
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
ACCOUNT_AUTHENTICATION_METHOD = "username_email"
SOCIALACCOUNT_EMAIL_VERIFICATION = "none"
SOCIALACCOUNT_AUTO_SIGNUP = False
CORS_ORIGIN_REGEX_WHITELIST = (
'^http://(.+)\.readthedocs\.org$',
'^https://(.+)\.readthedocs\.org$')
# So people can post to their accounts
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'origin',
'authorization',
'x-csrftoken'
)
# set GitHub scope
SOCIALACCOUNT_PROVIDERS = {
'github': {'SCOPE': ['user:email', 'read:org', 'admin:repo_hook', 'repo:status']}
}
ROOT_URLCONF = 'readthedocs.urls'
TEMPLATE_DIRS = (
TEMPLATE_ROOT,
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
# Read the Docs processor
"readthedocs.core.context_processors.readthedocs_processor",
)
INSTALLED_APPS = [
# Application classes
@property
def INSTALLED_APPS(self): # noqa
apps = [
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.contenttypes',
@ -222,87 +109,198 @@ INSTALLED_APPS = [
'allauth.socialaccount.providers.github',
'allauth.socialaccount.providers.bitbucket',
'allauth.socialaccount.providers.bitbucket_oauth2',
]
]
if self.DEBUG:
apps.append('django_extensions')
return apps
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
'PAGINATE_BY': 10
}
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
if DEBUG:
INSTALLED_APPS.append('django_extensions')
MIDDLEWARE_CLASSES = (
'readthedocs.core.middleware.ProxyMiddleware',
'readthedocs.core.middleware.FooterNoSessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'djangosecure.middleware.SecurityMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'pagination.middleware.PaginationMiddleware',
# Hack
# 'core.underscore_middleware.UnderscoreMiddleware',
'readthedocs.core.middleware.SubdomainMiddleware',
'readthedocs.core.middleware.SingleVersionMiddleware',
'corsheaders.middleware.CorsMiddleware',
# 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)
CELERY_ALWAYS_EAGER = True
CELERYD_TASK_TIME_LIMIT = 60 * 60 # 60 minutes
CELERY_SEND_TASK_ERROR_EMAILS = False
CELERYD_HIJACK_ROOT_LOGGER = False
# Don't queue a bunch of tasks in the workers
CELERYD_PREFETCH_MULTIPLIER = 1
CELERY_CREATE_MISSING_QUEUES = True
AUTHENTICATION_BACKENDS = (
# Needed to login by username in Django admin, regardless of `allauth`
"django.contrib.auth.backends.ModelBackend",
# `allauth` specific authentication methods, such as login by e-mail
"allauth.account.auth_backends.AuthenticationBackend",
)
CELERY_DEFAULT_QUEUE = 'celery'
# Wildcards not supported: https://github.com/celery/celery/issues/150
CELERY_ROUTES = {
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
# Read the Docs processor
"readthedocs.core.context_processors.readthedocs_processor",
)
# Paths
SITE_ROOT = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
TEMPLATE_ROOT = os.path.join(SITE_ROOT, 'readthedocs', 'templates')
DOCROOT = os.path.join(SITE_ROOT, 'user_builds')
UPLOAD_ROOT = os.path.join(SITE_ROOT, 'user_uploads')
CNAME_ROOT = os.path.join(SITE_ROOT, 'cnames')
LOGS_ROOT = os.path.join(SITE_ROOT, 'logs')
PRODUCTION_ROOT = os.path.join(SITE_ROOT, 'prod_artifacts')
PRODUCTION_MEDIA_ARTIFACTS = os.path.join(PRODUCTION_ROOT, 'media')
# Assets and media
STATIC_ROOT = os.path.join(SITE_ROOT, 'media/static/')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(SITE_ROOT, 'media/')
MEDIA_URL = '/media/'
ADMIN_MEDIA_PREFIX = '/media/admin/'
STATICFILES_DIRS = [os.path.join(SITE_ROOT, 'readthedocs', 'static')]
TEMPLATE_DIRS = (
TEMPLATE_ROOT,
)
# Cache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'PREFIX': 'docs',
}
}
CACHE_MIDDLEWARE_SECONDS = 60
# I18n
TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
LANGUAGES = (
('en', gettext('English')),
('es', gettext('Spanish')),
('nb', gettext('Norwegian Bokmål')),
('fr', gettext('French')),
('ru', gettext('Russian')),
('de', gettext('German')),
('gl', gettext('Galician')),
('vi', gettext('Vietnamese')),
('zh-cn', gettext('Chinese')),
('zh-tw', gettext('Taiwanese')),
('ja', gettext('Japanese')),
('uk', gettext('Ukrainian')),
('it', gettext('Italian')),
)
LOCALE_PATHS = [
os.path.join(SITE_ROOT, 'readthedocs', 'locale'),
]
USE_I18N = True
USE_L10N = True
# Celery
CELERY_ALWAYS_EAGER = True
CELERYD_TASK_TIME_LIMIT = 60 * 60 # 60 minutes
CELERY_SEND_TASK_ERROR_EMAILS = False
CELERYD_HIJACK_ROOT_LOGGER = False
# Don't queue a bunch of tasks in the workers
CELERYD_PREFETCH_MULTIPLIER = 1
CELERY_CREATE_MISSING_QUEUES = True
CELERY_DEFAULT_QUEUE = 'celery'
# Wildcards not supported: https://github.com/celery/celery/issues/150
CELERY_ROUTES = {
'readthedocs.oauth.tasks.SyncBitBucketRepositories': {
'queue': 'web',
},
'readthedocs.oauth.tasks.SyncGitHubRepositories': {
'queue': 'web',
},
}
}
DEFAULT_FROM_EMAIL = "no-reply@readthedocs.org"
SERVER_EMAIL = DEFAULT_FROM_EMAIL
SESSION_COOKIE_DOMAIN = 'readthedocs.org'
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
# Docker
DOCKER_ENABLE = False
DOCKER_IMAGE = 'rtfd-build'
HAYSTACK_CONNECTIONS = {
# All auth
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
ACCOUNT_AUTHENTICATION_METHOD = "username_email"
ACCOUNT_ACTIVATION_DAYS = 7
SOCIALACCOUNT_EMAIL_VERIFICATION = "none"
SOCIALACCOUNT_AUTO_SIGNUP = False
SOCIALACCOUNT_PROVIDERS = {
'github': {
'SCOPE': ['user:email', 'read:org', 'admin:repo_hook', 'repo:status']
}
}
# CORS
CORS_ORIGIN_REGEX_WHITELIST = (
'^http://(.+)\.readthedocs\.org$',
'^https://(.+)\.readthedocs\.org$')
# So people can post to their accounts
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'origin',
'authorization',
'x-csrftoken'
)
# RTD Settings
REPO_LOCK_SECONDS = 30
ALLOW_PRIVATE_REPOS = False
GROK_API_HOST = 'https://api.grokthedocs.com'
# Haystack
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
},
}
}
# Elasticsearch settings.
ES_HOSTS = ['127.0.0.1:9200']
ES_DEFAULT_NUM_REPLICAS = 0
ES_DEFAULT_NUM_SHARDS = 5
# Elasticsearch settings.
ES_HOSTS = ['127.0.0.1:9200']
ES_DEFAULT_NUM_REPLICAS = 0
ES_DEFAULT_NUM_SHARDS = 5
ALLOWED_HOSTS = ['*']
ALLOWED_HOSTS = ['*']
ABSOLUTE_URL_OVERRIDES = {
ABSOLUTE_URL_OVERRIDES = {
'auth.user': lambda o: "/profiles/%s/" % o.username
}
}
INTERNAL_IPS = ('127.0.0.1',)
INTERNAL_IPS = ('127.0.0.1',)
backup_count = 1000
maxBytes = 500 * 100 * 100
if LOG_DEBUG:
backup_count = 2
maxBytes = 500 * 100 * 10
# Guardian Settings
GUARDIAN_RAISE_403 = True
ANONYMOUS_USER_ID = -1
# Guardian Settings
GUARDIAN_RAISE_403 = True
ANONYMOUS_USER_ID = -1
# Stripe
STRIPE_SECRET = None
STRIPE_PUBLISHABLE = None
# Stripe
STRIPE_SECRET = None
STRIPE_PUBLISHABLE = None
# RTD Settings
REPO_LOCK_SECONDS = 30
ALLOW_PRIVATE_REPOS = False
GLOBAL_ANALYTICS_CODE = 'UA-17997319-1'
GRAVATAR_DEFAULT_IMAGE = 'http://media.readthedocs.org/images/silhouette.png'
COPY_START_YEAR = 2010
LOG_FORMAT = "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s"
RESTRUCTUREDTEXT_FILTER_SETTINGS = {
# Misc application settings
GLOBAL_ANALYTICS_CODE = 'UA-17997319-1'
GRAVATAR_DEFAULT_IMAGE = 'http://media.readthedocs.org/images/silhouette.png'
COPY_START_YEAR = 2010
RESTRICTEDSESSIONS_AUTHED_ONLY = True
RESTRUCTUREDTEXT_FILTER_SETTINGS = {
'cloak_email_addresses': True,
'file_insertion_enabled': False,
'raw_enabled': False,
@ -314,9 +312,16 @@ RESTRUCTUREDTEXT_FILTER_SETTINGS = {
'syntax_highlight': 'none',
'math_output': 'latex',
'field_name_limit': 50,
}
}
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
'PAGINATE_BY': 10
}
SILENCED_SYSTEM_CHECKS = ['fields.W342']
LOGGING = {
# Logging
LOG_FORMAT = "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s"
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
@ -339,56 +344,42 @@ LOGGING = {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOGS_ROOT, "exceptions.log"),
'maxBytes': maxBytes,
'backupCount': backup_count,
'formatter': 'standard',
},
'errorlog': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOGS_ROOT, "rtd.log"),
'maxBytes': maxBytes,
'backupCount': backup_count,
'formatter': 'standard',
},
'postcommit': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOGS_ROOT, "postcommit.log"),
'maxBytes': maxBytes,
'backupCount': backup_count,
'formatter': 'standard',
},
'middleware': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOGS_ROOT, "middleware.log"),
'maxBytes': maxBytes,
'backupCount': backup_count,
'formatter': 'standard',
},
'restapi': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOGS_ROOT, "api.log"),
'maxBytes': maxBytes,
'backupCount': backup_count,
'formatter': 'standard',
},
'db': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOGS_ROOT, "db.log"),
'maxBytes': maxBytes,
'backupCount': backup_count,
'formatter': 'standard',
},
'search': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOGS_ROOT, "search.log"),
'maxBytes': maxBytes,
'backupCount': backup_count,
'formatter': 'standard',
},
'mail_admins': {
@ -397,7 +388,7 @@ LOGGING = {
'class': 'django.utils.log.AdminEmailHandler',
},
'console': {
'level': 'INFO',
'level': ('INFO', 'DEBUG')[DEBUG],
'class': 'logging.StreamHandler',
'formatter': 'standard'
},
@ -457,7 +448,4 @@ LOGGING = {
'level': 'INFO',
},
}
}
if DEBUG:
LOGGING['handlers']['console']['level'] = 'DEBUG'
}

View File

@ -0,0 +1,62 @@
import os
from readthedocs.core.settings import Settings
from .base import CommunityBaseSettings
class CommunityDevSettings(CommunityBaseSettings):
"""Settings for local development"""
PRODUCTION_DOMAIN = 'localhost:8000'
WEBSOCKET_HOST = 'localhost:8088'
@property
def DATABASES(self): # noqa
return {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(self.SITE_ROOT, 'dev.db'),
}
}
DONT_HIT_DB = False
SESSION_COOKIE_DOMAIN = None
CACHE_BACKEND = 'dummy://'
SLUMBER_USERNAME = 'test'
SLUMBER_PASSWORD = 'test' # noqa: ignore dodgy check
SLUMBER_API_HOST = 'http://localhost:8000'
BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ALWAYS_EAGER = True
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
},
}
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
FILE_SYNCER = 'readthedocs.privacy.backends.syncers.LocalSyncer'
NGINX_X_ACCEL_REDIRECT = True
# For testing locally. Put this in your /etc/hosts:
# 127.0.0.1 test
# and navigate to http://test:8000
CORS_ORIGIN_WHITELIST = (
'test:8000',
)
CommunityDevSettings.load_settings(__name__)
if not os.environ.get('DJANGO_SETTINGS_SKIP_LOCAL', False):
try:
# pylint: disable=unused-wildcard-import
from .local_settings import * # noqa
except ImportError:
pass

View File

@ -1,56 +0,0 @@
import os
from .base import * # noqa
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(SITE_ROOT, 'dev.db'),
}
}
BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ALWAYS_EAGER = False
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
'PATH': os.path.join(SITE_ROOT, 'whoosh_index'),
},
}
CACHES = {
'default': {
'BACKEND': 'redis_cache.cache.RedisCache',
'LOCATION': 'localhost:6379',
'PREFIX': 'docs',
'OPTIONS': {
'DB': 1,
'CLIENT_CLASS': 'redis_cache.client.DefaultClient',
},
},
}
SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
SLUMBER_API_HOST = 'http://localhost:8000'
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTOCOL", "https")
SESSION_COOKIE_DOMAIN = None
SLUMBER_USERNAME = 'test'
SLUMBER_PASSWORD = 'test' # noqa
SLUMBER_API_HOST = 'http://localhost:8000'
WEBSOCKET_HOST = 'localhost:8088'
DONT_HIT_DB = False
# PRODUCTION_DOMAIN = 'readthedocs.org'
# USE_SUBDOMAIN = True
if not os.environ.get('DJANGO_SETTINGS_SKIP_LOCAL', False):
try:
from local_settings import * # noqa
except ImportError:
pass

View File

@ -1,78 +0,0 @@
import os
from .base import * # noqa
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'docs',
'USER': 'postgres', # Not used with sqlite3.
'PASSWORD': '',
'HOST': '10.177.73.97',
'PORT': '',
}
}
DEBUG = False
TEMPLATE_DEBUG = False
CELERY_ALWAYS_EAGER = False
MEDIA_URL = 'https://media.readthedocs.org/'
STATIC_URL = 'https://media.readthedocs.org/static/'
ADMIN_MEDIA_PREFIX = MEDIA_URL + 'admin/'
SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.solr_backend.SolrEngine',
'URL': 'http://odin:8983/solr',
}
}
CACHES = {
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': 'localhost:6379',
'PREFIX': 'docs',
'OPTIONS': {
'DB': 1,
'PARSER_CLASS': 'redis.connection.HiredisParser'
},
},
}
# Elasticsearch settings.
ES_HOSTS = ['backup:9200', 'db:9200']
ES_DEFAULT_NUM_REPLICAS = 1
ES_DEFAULT_NUM_SHARDS = 5
SLUMBER_API_HOST = 'https://readthedocs.org'
WEBSOCKET_HOST = 'websocket.readthedocs.org:8088'
PRODUCTION_DOMAIN = 'readthedocs.org'
USE_SUBDOMAIN = True
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
# Lock builds for 10 minutes
REPO_LOCK_SECONDS = 300
# Don't re-confirm existing accounts
ACCOUNT_EMAIL_VERIFICATION = 'none'
FILE_SYNCER = 'privacy.backends.syncers.DoubleRemotePuller'
# set GitHub scope
SOCIALACCOUNT_PROVIDERS = {
'github': {'SCOPE': ['user:email', 'read:org', 'admin:repo_hook', 'repo:status']}
}
# allauth settings
ACCOUNT_DEFAULT_HTTP_PROTOCOL = 'https'
if not os.environ.get('DJANGO_SETTINGS_SKIP_LOCAL', False):
try:
from local_settings import * # noqa
except ImportError:
pass

View File

@ -1,51 +0,0 @@
import os
from .base import * # noqa
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(SITE_ROOT, 'dev.db'),
}
}
BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
# CELERY_ALWAYS_EAGER = False
SESSION_COOKIE_DOMAIN = None
CACHE_BACKEND = 'dummy://'
SLUMBER_USERNAME = 'test'
SLUMBER_PASSWORD = 'test' # noqa: ignore dodgy check
SLUMBER_API_HOST = 'http://localhost:8000'
# GROK_API_HOST = 'http://localhost:5555'
PRODUCTION_DOMAIN = 'localhost:8000'
WEBSOCKET_HOST = 'localhost:8088'
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
},
}
DONT_HIT_DB = False
CELERY_ALWAYS_EAGER = True
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
FILE_SYNCER = 'readthedocs.privacy.backends.syncers.LocalSyncer'
# For testing locally. Put this in your /etc/hosts:
# 127.0.0.1 test
# and navigate to http://test:8000
CORS_ORIGIN_WHITELIST = (
'test:8000',
)
if not os.environ.get('DJANGO_SETTINGS_SKIP_LOCAL', False):
try:
from local_settings import * # noqa
except ImportError:
pass

View File

@ -1,13 +1,20 @@
import os
from .sqlite import * # noqa
from .dev import CommunityDevSettings
SLUMBER_USERNAME = 'test'
SLUMBER_PASSWORD = 'test'
SLUMBER_API_HOST = 'http://localhost:8000'
# A bunch of our tests check this value in a returned URL/Domain
PRODUCTION_DOMAIN = 'readthedocs.org'
GROK_API_HOST = 'http://localhost:8888'
class CommunityTestSettings(CommunityDevSettings):
SLUMBER_USERNAME = 'test'
SLUMBER_PASSWORD = 'test'
SLUMBER_API_HOST = 'http://localhost:8000'
# A bunch of our tests check this value in a returned URL/Domain
PRODUCTION_DOMAIN = 'readthedocs.org'
GROK_API_HOST = 'http://localhost:8888'
CommunityTestSettings.load_settings(__name__)
CACHES = {
'default': {

View File

@ -1,3 +1,7 @@
# pylint: disable=missing-docstring
from operator import add
from django.conf.urls import url, patterns, include
from django.contrib import admin
from django.conf import settings
@ -8,9 +12,9 @@ from tastypie.api import Api
from readthedocs.api.base import (ProjectResource, UserResource,
VersionResource, FileResource)
from readthedocs.core.urls import docs_urls, core_urls, deprecated_urls
from readthedocs.core.views import HomepageView, SupportView
from readthedocs.core.urls import docs_urls, core_urls, deprecated_urls
v1_api = Api(api_name='v1')
v1_api.register(UserResource())
@ -23,8 +27,7 @@ admin.autodiscover()
handler500 = 'readthedocs.core.views.server_error'
handler404 = 'readthedocs.core.views.server_error_404'
urlpatterns = patterns(
basic_urls = patterns(
'', # base view, flake8 complains if it is on the previous line.
url(r'^$', HomepageView.as_view(), name='homepage'),
url(r'^support/', SupportView.as_view(), name='support'),
@ -33,7 +36,6 @@ urlpatterns = patterns(
rtd_urls = patterns(
'',
url(r'^projects/', include('readthedocs.projects.urls.public')),
url(r'^bookmarks/', include('readthedocs.bookmarks.urls')),
url(r'^search/$', 'readthedocs.search.views.elastic_search', name='search'),
url(r'^dashboard/', include('readthedocs.projects.urls.private')),
@ -44,6 +46,11 @@ rtd_urls = patterns(
url(r'^builds/', include('readthedocs.builds.urls')),
)
project_urls = patterns(
'',
url(r'^projects/', include('readthedocs.projects.urls.public')),
)
api_urls = patterns(
'',
url(r'^api/', include(v1_api.urls)),
@ -68,22 +75,24 @@ money_urls = patterns(
url(r'^accounts/gold/', include('readthedocs.gold.urls')),
)
if not getattr(settings, 'USE_SUBDOMAIN', False):
urlpatterns += docs_urls
urlpatterns += rtd_urls
urlpatterns += api_urls
urlpatterns += core_urls
urlpatterns += i18n_urls
urlpatterns += money_urls
urlpatterns += deprecated_urls
if getattr(settings, 'ALLOW_ADMIN', True):
urlpatterns += admin_urls
if settings.DEBUG:
urlpatterns += patterns(
debug_urls = add(
patterns(
'', # base view, flake8 complains if it is on the previous line.
url('style-catalog/$',
TemplateView.as_view(template_name='style_catalog.html')),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
),
static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
)
# Export URLs
groups = [basic_urls, rtd_urls, project_urls, api_urls, core_urls, i18n_urls,
money_urls, deprecated_urls]
if not getattr(settings, 'USE_SUBDOMAIN', False):
groups.insert(0, docs_urls)
if getattr(settings, 'ALLOW_ADMIN', True):
groups.append(admin_urls)
if getattr(settings, 'DEBUG', False):
groups.append(debug_urls)
urlpatterns = reduce(add, groups)