settings: Unset STATIC_ROOT in development.

Django’s default FileSystemFinder disallows STATICFILES_DIRS from
containing STATIC_ROOT (by raising an ImproperlyConfigured exception),
because STATIC_ROOT is supposed to be the result of collecting all the
static files in the project, not one of the potentially many sources
of static files.

Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
This commit is contained in:
Anders Kaseorg 2019-07-16 17:29:08 -07:00 committed by Tim Abbott
parent a97a2612bb
commit fd7803e7f4
13 changed files with 40 additions and 33 deletions

View File

@ -50,6 +50,7 @@ from zerver.lib.realm_logo import realm_logo_url
from zerver.lib.retention import move_messages_to_archive
from zerver.lib.send_email import send_email, FromAddress, send_email_to_admins, \
clear_scheduled_emails, clear_scheduled_invitation_emails
from zerver.lib.storage import static_path
from zerver.lib.stream_subscription import (
get_active_subscriptions_for_stream_id,
get_active_subscriptions_for_stream_ids,
@ -2916,7 +2917,7 @@ def bulk_add_subscriptions(streams: Iterable[Stream],
already_subscribed)
def get_available_notification_sounds() -> List[str]:
notification_sounds_path = os.path.join(settings.STATIC_ROOT, 'audio/notification_sounds')
notification_sounds_path = static_path('audio/notification_sounds')
available_notification_sounds = []
for file_name in os.listdir(notification_sounds_path):

View File

@ -34,6 +34,7 @@ from zerver.lib.camo import get_camo_url
from zerver.lib.emoji import translate_emoticons, emoticon_regex
from zerver.lib.mention import possible_mentions, \
possible_user_group_mentions, extract_user_group
from zerver.lib.storage import static_path
from zerver.lib.url_encoding import encode_stream, hash_util_encode
from zerver.lib.thumbnail import user_uploads_or_external
from zerver.lib.timeout import timeout, TimeoutExpired
@ -1166,13 +1167,11 @@ def possible_avatar_emails(content: str) -> Set[str]:
return emails
path_to_name_to_codepoint = os.path.join(settings.STATIC_ROOT,
"generated", "emoji", "name_to_codepoint.json")
path_to_name_to_codepoint = static_path("generated/emoji/name_to_codepoint.json")
with open(path_to_name_to_codepoint) as name_to_codepoint_file:
name_to_codepoint = ujson.load(name_to_codepoint_file)
path_to_codepoint_to_name = os.path.join(settings.STATIC_ROOT,
"generated", "emoji", "codepoint_to_name.json")
path_to_codepoint_to_name = static_path("generated/emoji/codepoint_to_name.json")
with open(path_to_codepoint_to_name) as codepoint_to_name_file:
codepoint_to_name = ujson.load(codepoint_to_name_file)

View File

@ -4,6 +4,7 @@ import os
from typing import Any, Dict, List, Optional
from django.conf import settings
from zerver.lib.storage import static_path
# See https://jackstromberg.com/2013/01/useraccountcontrol-attributeflag-values/
# for docs on what these values mean.
@ -21,7 +22,7 @@ def generate_dev_ldap_dir(mode: str, num_users: int=8) -> Dict[str, Dict[str, An
ldap_data.append((name, email, phone_number, birthdate))
profile_images = [open(path, "rb").read() for path in
glob.glob(os.path.join(settings.STATIC_ROOT, "images/team/*"))]
glob.glob(os.path.join(static_path("images/team"), "*"))]
ldap_dir = {}
for i, user_data in enumerate(ldap_data):
email = user_data[1].lower()

View File

@ -3,15 +3,15 @@ import os
import re
import ujson
from django.conf import settings
from django.utils.translation import ugettext as _
from typing import Optional, Tuple
from zerver.lib.request import JsonableError
from zerver.lib.storage import static_path
from zerver.lib.upload import upload_backend
from zerver.models import Reaction, Realm, RealmEmoji, UserProfile
EMOJI_PATH = os.path.join(settings.STATIC_ROOT, "generated", "emoji")
EMOJI_PATH = static_path("generated/emoji")
NAME_TO_CODEPOINT_PATH = os.path.join(EMOJI_PATH, "name_to_codepoint.json")
CODEPOINT_TO_NAME_PATH = os.path.join(EMOJI_PATH, "codepoint_to_name.json")
EMOTICON_CONVERSIONS_PATH = os.path.join(EMOJI_PATH, "emoticon_conversions.json")

View File

@ -7,6 +7,7 @@ from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls.resolvers import LocaleRegexProvider
from django.utils.module_loading import import_string
from django.utils.translation import ugettext as _
from zerver.lib.storage import static_path
"""This module declares all of the (documented) integrations available
@ -86,9 +87,9 @@ class Integration:
def get_logo_url(self) -> Optional[str]:
logo_file_path_svg = self.DEFAULT_LOGO_STATIC_PATH_SVG.format(name=self.name)
logo_file_path_png = self.DEFAULT_LOGO_STATIC_PATH_PNG.format(name=self.name)
if os.path.isfile(os.path.join(settings.STATIC_ROOT, logo_file_path_svg)):
if os.path.isfile(static_path(logo_file_path_svg)):
return staticfiles_storage.url(logo_file_path_svg)
elif os.path.isfile(os.path.join(settings.STATIC_ROOT, logo_file_path_png)):
elif os.path.isfile(static_path(logo_file_path_png)):
return staticfiles_storage.url(logo_file_path_png)
return None

View File

@ -7,6 +7,15 @@ from django.conf import settings
from django.contrib.staticfiles.storage import ManifestStaticFilesStorage
from pipeline.storage import PipelineMixin
if not settings.PIPELINE_ENABLED:
from django.contrib.staticfiles.finders import find
def static_path(path: str) -> str:
return find(path) or "/nonexistent"
else:
def static_path(path: str) -> str:
return os.path.join(settings.STATIC_ROOT, path)
class IgnoreBundlesManifestStaticFilesStorage(ManifestStaticFilesStorage):
def hashed_name(self, name: str, content: Optional[str]=None, filename: Optional[str]=None) -> str:
ext = os.path.splitext(name)[1]

View File

@ -4,6 +4,7 @@ import os
import subprocess
from django.conf import settings
from typing import Optional
from zerver.lib.storage import static_path
def render_tex(tex: str, is_inline: bool=True) -> Optional[str]:
r"""Render a TeX string into HTML using KaTeX
@ -20,7 +21,7 @@ def render_tex(tex: str, is_inline: bool=True) -> Optional[str]:
"""
katex_path = (
os.path.join(settings.STATIC_ROOT, "webpack-bundles/katex-cli.js")
static_path("webpack-bundles/katex-cli.js")
if settings.PRODUCTION
else os.path.join(settings.DEPLOY_ROOT, "node_modules/katex/cli.js")
)

View File

@ -11,7 +11,6 @@ from django.core import signing
from django.urls import reverse
import httpretty
import os
import jwt
import mock
@ -35,6 +34,7 @@ from zerver.lib.mobile_auth_otp import otp_decrypt_api_key
from zerver.lib.validator import validate_login_email, \
check_bool, check_dict_only, check_string, Validator
from zerver.lib.request import JsonableError
from zerver.lib.storage import static_path
from zerver.lib.users import get_all_api_keys
from zerver.lib.upload import resize_avatar, MEDIUM_AVATAR_SIZE
from zerver.lib.initial_password import initial_password
@ -2506,7 +2506,7 @@ class TestLDAP(ZulipLDAPTestCase):
'uid=nonexisting,ou=users,dc=acme,dc=com': {
'cn': ['NonExisting', ],
'userPassword': ['testing', ],
'thumbnailPhoto': [open(os.path.join(settings.STATIC_ROOT, "images/team/tim.png"), "rb").read()],
'thumbnailPhoto': [open(static_path("images/team/tim.png"), "rb").read()],
}
}
with self.settings(
@ -2640,7 +2640,7 @@ class TestZulipLDAPUserPopulator(ZulipLDAPTestCase):
self.mock_ldap.directory = {
'uid=hamlet,ou=users,dc=zulip,dc=com': {
'cn': ['King Hamlet', ],
'thumbnailPhoto': [open(os.path.join(settings.STATIC_ROOT, "images/team/tim.png"), "rb").read()]
'thumbnailPhoto': [open(static_path("images/team/tim.png"), "rb").read()]
}
}
with mock.patch('zerver.lib.upload.upload_avatar_image') as fn, \
@ -2662,7 +2662,7 @@ class TestZulipLDAPUserPopulator(ZulipLDAPTestCase):
self.mock_ldap.directory = {
'uid=hamlet,ou=users,dc=zulip,dc=com': {
'cn': ['King Hamlet', ],
'thumbnailPhoto': [open(os.path.join(settings.STATIC_ROOT, "images/logo/zulip-icon-512x512.png"), "rb").read()]
'thumbnailPhoto': [open(static_path("images/logo/zulip-icon-512x512.png"), "rb").read()]
}
}
with mock.patch('zerver.lib.upload.upload_avatar_image') as fn, \
@ -2852,7 +2852,7 @@ class TestQueryLDAP(ZulipLDAPTestCase):
attrs = {
'cn': ['King Hamlet', ],
'sn': ['Hamlet', ],
'thumbnailPhoto': [open(os.path.join(settings.STATIC_ROOT, "images/team/tim.png"), "rb").read()],
'thumbnailPhoto': [open(static_path("images/team/tim.png"), "rb").read()],
'birthDate': ['1990-01-01', ],
'twitter': ['@handle', ],
}

View File

@ -4,13 +4,13 @@ import os
import subprocess
import ujson
from django.conf import settings
from django.test import TestCase, override_settings
from django.http import HttpResponse
from typing import Any, Dict, List
from zproject.settings import DEPLOY_ROOT
from zerver.lib.integrations import INTEGRATIONS
from zerver.lib.storage import static_path
from zerver.lib.test_classes import ZulipTestCase
from zerver.lib.test_helpers import HostRequestMock
from zerver.lib.test_runner import slow
@ -346,7 +346,7 @@ class AboutPageTest(ZulipTestCase):
"""
# This block has unreliable test coverage due to the implicit
# caching here, so we exclude it from coverage.
if not os.path.exists(settings.CONTRIBUTORS_DATA):
if not os.path.exists(static_path('generated/github-contributors.json')):
# Copy the fixture file in `zerver/tests/fixtures` to `static/generated`
update_script = os.path.join(os.path.dirname(__file__),
'../../tools/update-authors-json') # nocoverage

View File

@ -12,13 +12,13 @@ from zerver.lib.bugdown import privacy_clean_markdown
from zerver.lib.request import has_request_variables, REQ
from zerver.lib.response import json_success
from zerver.lib.queue import queue_json_publish
from zerver.lib.storage import static_path
from zerver.lib.unminify import SourceMap
from zerver.lib.utils import statsd, statsd_key
from zerver.lib.validator import check_bool, check_dict
from zerver.models import UserProfile
import subprocess
import os
import logging
js_source_map = None # type: Optional[SourceMap]
@ -28,7 +28,7 @@ def get_js_source_map() -> Optional[SourceMap]:
global js_source_map
if not js_source_map and not (settings.DEVELOPMENT or settings.TEST_SUITE):
js_source_map = SourceMap([
os.path.join(settings.STATIC_ROOT, 'webpack-bundles')
static_path('webpack-bundles')
])
return js_source_map

View File

@ -23,6 +23,7 @@ from zerver.lib.exceptions import CannotDeactivateLastUserError
from zerver.lib.integrations import EMBEDDED_BOTS
from zerver.lib.request import has_request_variables, REQ
from zerver.lib.response import json_error, json_success
from zerver.lib.storage import static_path
from zerver.lib.streams import access_stream_by_name
from zerver.lib.upload import upload_avatar_image
from zerver.lib.users import get_api_key
@ -521,7 +522,7 @@ def get_profile_backend(request: HttpRequest, user_profile: UserProfile) -> Http
return json_success(result)
def team_view(request: HttpRequest) -> HttpResponse:
with open(settings.CONTRIBUTORS_DATA) as f:
with open(static_path('generated/github-contributors.json')) as f:
data = ujson.load(f)
return render(

View File

@ -21,6 +21,7 @@ from zerver.lib.cache import cache_set
from zerver.lib.generate_test_data import create_test_data
from zerver.lib.onboarding import create_if_missing_realm_internal_bots
from zerver.lib.push_notifications import logger as push_notifications_logger
from zerver.lib.storage import static_path
from zerver.lib.users import add_service
from zerver.lib.url_preview.preview import CACHE_NAME as PREVIEW_CACHE_NAME
from zerver.lib.user_groups import create_user_group
@ -407,7 +408,7 @@ class Command(BaseCommand):
user_profiles = list(UserProfile.objects.filter(is_bot=False)) # type: List[UserProfile]
# Create a test realm emoji.
IMAGE_FILE_PATH = os.path.join(settings.STATIC_ROOT, 'images', 'test-images', 'checkbox.png')
IMAGE_FILE_PATH = static_path('images/test-images/checkbox.png')
with open(IMAGE_FILE_PATH, 'rb') as fp:
check_add_realm_emoji(zulip_realm, 'green_tick', iago, fp)

View File

@ -873,14 +873,7 @@ STATIC_URL = '/static/'
# here so that urls.py can read it.
PIPELINE_ENABLED = not DEBUG
if not PIPELINE_ENABLED:
STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage'
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'pipeline.finders.PipelineFinder',
)
STATIC_ROOT = os.path.abspath(os.path.join(DEPLOY_ROOT, 'static/'))
else:
if PIPELINE_ENABLED:
STATICFILES_STORAGE = 'zerver.lib.storage.ZulipStorage'
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
@ -968,7 +961,9 @@ default_template_engine_settings.update({
# The webhook integration templates
os.path.join(DEPLOY_ROOT, 'zerver', 'webhooks'),
# The python-zulip-api:zulip_bots package templates
os.path.join(STATIC_ROOT, 'generated', 'bots'),
os.path.join(
STATIC_ROOT if PIPELINE_ENABLED else 'static', 'generated', 'bots'
),
],
'APP_DIRS': True,
})
@ -1417,6 +1412,4 @@ CROSS_REALM_BOT_EMAILS = {
'emailgateway@zulip.com',
}
CONTRIBUTORS_DATA = os.path.join(STATIC_ROOT, 'generated/github-contributors.json')
THUMBOR_KEY = get_secret('thumbor_key')