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 overridebreak-out-core-urls-views
parent
d17b50433b
commit
b749c5022f
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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('_', '-')
|
||||
|
|
|
@ -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)
|
|
@ -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,21 +242,20 @@ 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)
|
||||
run('ln -nsf %s/ %s' % (docs_dir, symlink))
|
||||
# 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):
|
||||
"""Symlink project's versions
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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/')
|
||||
|
|
|
@ -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):
|
||||
r = self.client.get('/docs/pip/usage.html')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
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):
|
||||
r = self.client.get('/docs/nonexistent/blah.html')
|
||||
self.assertEqual(r.status_code, 404)
|
||||
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/')
|
||||
|
|
|
@ -1,463 +1,451 @@
|
|||
# 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 = (
|
||||
('Eric Holscher', 'eric@readthedocs.org'),
|
||||
('Anthony Johnson', 'anthony@readthedocs.org'),
|
||||
)
|
||||
"""Community base settings, don't use this directly"""
|
||||
|
||||
MANAGERS = ADMINS
|
||||
# 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
|
||||
|
||||
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')
|
||||
# Debug settings
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
TASTYPIE_FULL_DEBUG = True
|
||||
LOG_DEBUG = False
|
||||
|
||||
# A new base for production files
|
||||
PRODUCTION_ROOT = os.path.join(SITE_ROOT, 'prod_artifacts')
|
||||
PRODUCTION_MEDIA_ARTIFACTS = os.path.join(PRODUCTION_ROOT, 'media')
|
||||
# Domains and URLs
|
||||
PRODUCTION_DOMAIN = 'readthedocs.org'
|
||||
PUBLIC_DOMAIN = None
|
||||
USE_SUBDOMAIN = False
|
||||
PUBLIC_API_URL = 'https://{0}'.format(PRODUCTION_DOMAIN)
|
||||
|
||||
MEDIA_ROOT = '%s/media/' % (SITE_ROOT)
|
||||
MEDIA_URL = '/media/'
|
||||
ADMIN_MEDIA_PREFIX = '/media/admin/'
|
||||
ADMINS = (
|
||||
('Eric Holscher', 'eric@readthedocs.org'),
|
||||
('Anthony Johnson', 'anthony@readthedocs.org'),
|
||||
)
|
||||
MANAGERS = ADMINS
|
||||
|
||||
GROK_API_HOST = 'https://api.grokthedocs.com'
|
||||
SILENCED_SYSTEM_CHECKS = ['fields.W342']
|
||||
# Email
|
||||
DEFAULT_FROM_EMAIL = "no-reply@readthedocs.org"
|
||||
SERVER_EMAIL = DEFAULT_FROM_EMAIL
|
||||
|
||||
# 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 = ()
|
||||
# Cookies
|
||||
SESSION_COOKIE_DOMAIN = 'readthedocs.org'
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
CSRF_COOKIE_HTTPONLY = True
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
|
||||
'PREFIX': 'docs',
|
||||
}
|
||||
}
|
||||
# Application classes
|
||||
@property
|
||||
def INSTALLED_APPS(self): # noqa
|
||||
apps = [
|
||||
'django.contrib.auth',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.humanize',
|
||||
|
||||
CACHE_MIDDLEWARE_SECONDS = 60
|
||||
# third party apps
|
||||
'pagination',
|
||||
'taggit',
|
||||
'djangosecure',
|
||||
'guardian',
|
||||
'django_gravatar',
|
||||
'rest_framework',
|
||||
'corsheaders',
|
||||
'copyright',
|
||||
'textclassifier',
|
||||
'annoying',
|
||||
'django_countries',
|
||||
|
||||
LOGIN_REDIRECT_URL = '/dashboard/'
|
||||
FORCE_WWW = False
|
||||
# APPEND_SLASH = False
|
||||
# Celery bits
|
||||
'djcelery',
|
||||
|
||||
# Docker
|
||||
DOCKER_ENABLE = False
|
||||
DOCKER_IMAGE = 'rtfd-build'
|
||||
# daniellindsleyrocksdahouse
|
||||
'haystack',
|
||||
'tastypie',
|
||||
|
||||
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'),
|
||||
]
|
||||
# our apps
|
||||
'readthedocs.bookmarks',
|
||||
'readthedocs.projects',
|
||||
'readthedocs.builds',
|
||||
'readthedocs.comments',
|
||||
'readthedocs.core',
|
||||
'readthedocs.doc_builder',
|
||||
'readthedocs.oauth',
|
||||
'readthedocs.redirects',
|
||||
'readthedocs.rtd_tests',
|
||||
'readthedocs.restapi',
|
||||
'readthedocs.privacy',
|
||||
'readthedocs.gold',
|
||||
'readthedocs.donate',
|
||||
'readthedocs.payments',
|
||||
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
SITE_ID = 1
|
||||
# allauth
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
'allauth.socialaccount.providers.github',
|
||||
'allauth.socialaccount.providers.bitbucket',
|
||||
'allauth.socialaccount.providers.bitbucket_oauth2',
|
||||
]
|
||||
if self.DEBUG:
|
||||
apps.append('django_extensions')
|
||||
return apps
|
||||
|
||||
SECRET_KEY = 'replace-this-please' # noqa: ignore dodgy check
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)
|
||||
|
||||
ATOMIC_REQUESTS = True
|
||||
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',
|
||||
)
|
||||
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)
|
||||
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",
|
||||
)
|
||||
|
||||
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',
|
||||
)
|
||||
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",
|
||||
)
|
||||
|
||||
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",
|
||||
)
|
||||
# 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')
|
||||
|
||||
# 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
|
||||
# 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,
|
||||
)
|
||||
|
||||
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 = [
|
||||
'django.contrib.auth',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.humanize',
|
||||
|
||||
# third party apps
|
||||
'pagination',
|
||||
'taggit',
|
||||
'djangosecure',
|
||||
'guardian',
|
||||
'django_gravatar',
|
||||
'rest_framework',
|
||||
'corsheaders',
|
||||
'copyright',
|
||||
'textclassifier',
|
||||
'annoying',
|
||||
'django_countries',
|
||||
|
||||
# Celery bits
|
||||
'djcelery',
|
||||
|
||||
# daniellindsleyrocksdahouse
|
||||
'haystack',
|
||||
'tastypie',
|
||||
|
||||
# our apps
|
||||
'readthedocs.bookmarks',
|
||||
'readthedocs.projects',
|
||||
'readthedocs.builds',
|
||||
'readthedocs.comments',
|
||||
'readthedocs.core',
|
||||
'readthedocs.doc_builder',
|
||||
'readthedocs.oauth',
|
||||
'readthedocs.redirects',
|
||||
'readthedocs.rtd_tests',
|
||||
'readthedocs.restapi',
|
||||
'readthedocs.privacy',
|
||||
'readthedocs.gold',
|
||||
'readthedocs.donate',
|
||||
'readthedocs.payments',
|
||||
|
||||
# allauth
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
'allauth.socialaccount.providers.github',
|
||||
'allauth.socialaccount.providers.bitbucket',
|
||||
'allauth.socialaccount.providers.bitbucket_oauth2',
|
||||
]
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
|
||||
'PAGINATE_BY': 10
|
||||
}
|
||||
|
||||
if DEBUG:
|
||||
INSTALLED_APPS.append('django_extensions')
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
ABSOLUTE_URL_OVERRIDES = {
|
||||
'auth.user': lambda o: "/profiles/%s/" % o.username
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
# 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 = {
|
||||
'cloak_email_addresses': True,
|
||||
'file_insertion_enabled': False,
|
||||
'raw_enabled': False,
|
||||
'strip_comments': True,
|
||||
'doctitle_xform': True,
|
||||
'sectsubtitle_xform': True,
|
||||
'initial_header_level': 2,
|
||||
'report_level': 5,
|
||||
'syntax_highlight': 'none',
|
||||
'math_output': 'latex',
|
||||
'field_name_limit': 50,
|
||||
}
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format': LOG_FORMAT,
|
||||
'datefmt': "%d/%b/%Y %H:%M:%S"
|
||||
},
|
||||
},
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
# Cache
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
|
||||
'PREFIX': 'docs',
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'null': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'django.utils.log.NullHandler',
|
||||
},
|
||||
'exceptionlog': {
|
||||
'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': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
'console': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'standard'
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django': {
|
||||
'handlers': ['console', 'errorlog'],
|
||||
'propagate': True,
|
||||
'level': 'WARN',
|
||||
},
|
||||
'django.db.backends': {
|
||||
'handlers': ['db'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'readthedocs.core.views.post_commit': {
|
||||
'handlers': ['postcommit'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'core.middleware': {
|
||||
'handlers': ['middleware'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'restapi': {
|
||||
'handlers': ['restapi'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'django.request': {
|
||||
'handlers': ['exceptionlog'],
|
||||
'level': 'ERROR',
|
||||
'propagate': False,
|
||||
},
|
||||
'readthedocs.projects.views.public.search': {
|
||||
'handlers': ['search'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'search': {
|
||||
'handlers': ['search'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
# Uncomment if you want to see Elasticsearch queries in the console.
|
||||
# 'elasticsearch.trace': {
|
||||
# 'level': 'DEBUG',
|
||||
# 'handlers': ['console'],
|
||||
# },
|
||||
}
|
||||
CACHE_MIDDLEWARE_SECONDS = 60
|
||||
|
||||
# Default handler for everything that we're doing. Hopefully this
|
||||
# doesn't double-print the Django things as well. Not 100% sure how
|
||||
# logging works :)
|
||||
'': {
|
||||
'handlers': ['console', 'errorlog'],
|
||||
'level': 'INFO',
|
||||
# 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',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if DEBUG:
|
||||
LOGGING['handlers']['console']['level'] = 'DEBUG'
|
||||
# Docker
|
||||
DOCKER_ENABLE = False
|
||||
DOCKER_IMAGE = 'rtfd-build'
|
||||
|
||||
# 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
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
ABSOLUTE_URL_OVERRIDES = {
|
||||
'auth.user': lambda o: "/profiles/%s/" % o.username
|
||||
}
|
||||
|
||||
INTERNAL_IPS = ('127.0.0.1',)
|
||||
|
||||
# Guardian Settings
|
||||
GUARDIAN_RAISE_403 = True
|
||||
ANONYMOUS_USER_ID = -1
|
||||
|
||||
# Stripe
|
||||
STRIPE_SECRET = None
|
||||
STRIPE_PUBLISHABLE = None
|
||||
|
||||
# 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,
|
||||
'strip_comments': True,
|
||||
'doctitle_xform': True,
|
||||
'sectsubtitle_xform': True,
|
||||
'initial_header_level': 2,
|
||||
'report_level': 5,
|
||||
'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
|
||||
LOG_FORMAT = "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s"
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format': LOG_FORMAT,
|
||||
'datefmt': "%d/%b/%Y %H:%M:%S"
|
||||
},
|
||||
},
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'null': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'django.utils.log.NullHandler',
|
||||
},
|
||||
'exceptionlog': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(LOGS_ROOT, "exceptions.log"),
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'errorlog': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(LOGS_ROOT, "rtd.log"),
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'postcommit': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(LOGS_ROOT, "postcommit.log"),
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'middleware': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(LOGS_ROOT, "middleware.log"),
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'restapi': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(LOGS_ROOT, "api.log"),
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'db': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(LOGS_ROOT, "db.log"),
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'search': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(LOGS_ROOT, "search.log"),
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
'console': {
|
||||
'level': ('INFO', 'DEBUG')[DEBUG],
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'standard'
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django': {
|
||||
'handlers': ['console', 'errorlog'],
|
||||
'propagate': True,
|
||||
'level': 'WARN',
|
||||
},
|
||||
'django.db.backends': {
|
||||
'handlers': ['db'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'readthedocs.core.views.post_commit': {
|
||||
'handlers': ['postcommit'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'core.middleware': {
|
||||
'handlers': ['middleware'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'restapi': {
|
||||
'handlers': ['restapi'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'django.request': {
|
||||
'handlers': ['exceptionlog'],
|
||||
'level': 'ERROR',
|
||||
'propagate': False,
|
||||
},
|
||||
'readthedocs.projects.views.public.search': {
|
||||
'handlers': ['search'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'search': {
|
||||
'handlers': ['search'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
# Uncomment if you want to see Elasticsearch queries in the console.
|
||||
# 'elasticsearch.trace': {
|
||||
# 'level': 'DEBUG',
|
||||
# 'handlers': ['console'],
|
||||
# },
|
||||
|
||||
# Default handler for everything that we're doing. Hopefully this
|
||||
# doesn't double-print the Django things as well. Not 100% sure how
|
||||
# logging works :)
|
||||
'': {
|
||||
'handlers': ['console', 'errorlog'],
|
||||
'level': 'INFO',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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': {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue