diff --git a/cms/envs/common.py b/cms/envs/common.py index 7a4cd7b77f..356fb2d7ff 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -2309,3 +2309,10 @@ VERIFY_STUDENT = { # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2020-11-02 ORGANIZATIONS_AUTOCREATE = True + +################# Settings for brand logos. ################# +LOGO_URL = None +LOGO_URL_PNG = None +LOGO_TRADEMARK_URL = None +FAVICON_URL = None +DEFAULT_EMAIL_LOGO_URL = 'https://edx-cdn.org/v3/default/logo.png' diff --git a/cms/envs/production.py b/cms/envs/production.py index cd515fcb56..8cf5473e43 100644 --- a/cms/envs/production.py +++ b/cms/envs/production.py @@ -568,3 +568,9 @@ if FEATURES.get('ENABLE_CORS_HEADERS'): CORS_ALLOW_HEADERS = corsheaders_default_headers + ( 'use-jwt-cookie', ) + +################# Settings for brand logos. ################# +LOGO_URL = ENV_TOKENS.get('LOGO_URL', LOGO_URL) +LOGO_URL_PNG = ENV_TOKENS.get('LOGO_URL_PNG', LOGO_URL_PNG) +LOGO_TRADEMARK_URL = ENV_TOKENS.get('LOGO_TRADEMARK_URL', LOGO_TRADEMARK_URL) +FAVICON_URL = ENV_TOKENS.get('FAVICON_URL', FAVICON_URL) diff --git a/lms/djangoapps/branding/api.py b/lms/djangoapps/branding/api.py index e532240dfe..4f4ade9abc 100644 --- a/lms/djangoapps/branding/api.py +++ b/lms/djangoapps/branding/api.py @@ -26,6 +26,7 @@ from six.moves.urllib.parse import urljoin from lms.djangoapps.branding.models import BrandingApiConfig from common.djangoapps.edxmako.shortcuts import marketing_link from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers +from .toggles import app_logs_enabled log = logging.getLogger("edx.footer") EMPTY_URL = '#' @@ -443,15 +444,32 @@ def _footer_mobile_links(is_secure): def _footer_logo_img(is_secure): - """Return the logo used for footer about link + """ + Return the logo used for footer about link - Args: + Arguments: is_secure (bool): Whether the request is using TLS. Returns: - Absolute url to logo + URL of the brand logo """ - logo_name = configuration_helpers.get_value('FOOTER_ORGANIZATION_IMAGE', settings.FOOTER_ORGANIZATION_IMAGE) + default_local_path = 'images/logo.png' + brand_footer_logo_url = settings.LOGO_TRADEMARK_URL + footer_url_from_site_config = configuration_helpers.get_value( + 'FOOTER_ORGANIZATION_IMAGE', + settings.FOOTER_ORGANIZATION_IMAGE + ) + + if app_logs_enabled(): + log.info( + ("[Branding][footer_logo_img]: site_config:%s, footer_org_img:%s," + "brand_url:%s, default:%s"), + footer_url_from_site_config, + settings.FOOTER_ORGANIZATION_IMAGE, + brand_footer_logo_url, + default_local_path + ) + # `logo_name` is looked up from the configuration, # which falls back on the Django settings, which loads it from # `lms.yml`, which is created and managed by Ansible. Because of @@ -461,25 +479,22 @@ def _footer_logo_img(is_secure): # EdX needs the FOOTER_ORGANIZATION_IMAGE value to point to edX's # logo by default, so that it can display properly on edx.org -- both # within the LMS, and on the Drupal marketing site, which uses this API. - try: - return _absolute_url_staticfile(is_secure, logo_name) - except ValueError: - # However, if the edx.org comprehensive theme is not activated, - # Django's staticfiles system will be unable to find this footer, - # and will throw a ValueError. Since the edx.org comprehensive theme - # is not activated by default, we will end up entering this block - # of code on new Open edX installations, and on sandbox installations. - # We can log when this happens: - default_logo = "images/logo.png" - log.info( - u"Failed to find footer logo at '%s', using '%s' instead", - logo_name, - default_logo, - ) - # And we'll use the default logo path of "images/logo.png" instead. - # There is a core asset that corresponds to this logo, so this should - # always succeed. - return staticfiles_storage.url(default_logo) + if footer_url_from_site_config: + return _absolute_url_staticfile(is_secure, footer_url_from_site_config) + + if brand_footer_logo_url: + return brand_footer_logo_url + + log.info( + "Failed to find footer logo at '%s', using '%s' instead", + footer_url_from_site_config, + default_local_path, + ) + + # And we'll use the default logo path of "images/logo.png" instead. + # There is a core asset that corresponds to this logo, so this should + # always succeed. + return staticfiles_storage.url(default_local_path) def _absolute_url(is_secure, url_path): @@ -564,27 +579,72 @@ def get_base_url(is_secure): def get_logo_url(is_secure=True): """ - Return the url for the branded logo image to be used + Return the url for the branded logo image to be used. + + Preference of the logo should be, + Look for site configuration override and return absolute url + Absolute url of brand Logo if defined in django settings + Relative default local image path + Arguments: is_secure (bool): If true, use HTTPS as the protocol. """ + brand_logo_url = settings.LOGO_URL + default_local_path = 'images/logo.png' + logo_url_from_site_config = configuration_helpers.get_value('logo_image_url') + university = configuration_helpers.get_value('university') - # if the configuration has an overide value for the logo_image_url - # let's use that - image_url = configuration_helpers.get_value('logo_image_url') - if image_url: - return _absolute_url_staticfile( - is_secure=is_secure, - name=image_url, + if app_logs_enabled(): + log.info( + ("[Branding][get_logo_url]: site_config:%s, university:%s, " + "brand_url:%s, default:%s"), + logo_url_from_site_config, + university, + brand_logo_url, + default_local_path ) - # otherwise, use the legacy means to configure this - university = configuration_helpers.get_value('university') + if logo_url_from_site_config: + return _absolute_url_staticfile(is_secure=is_secure, name=logo_url_from_site_config) if university: return staticfiles_storage.url('images/{uni}-on-edx-logo.png'.format(uni=university)) - else: - return staticfiles_storage.url('images/logo.png') + + if brand_logo_url: + return brand_logo_url + + return staticfiles_storage.url(default_local_path) + + +def get_favicon_url(): + """ + Return the url for the branded favicon image to be used. + + Preference of the icon should be, + Look for site configuration override + Brand favicon url is defined in settings + Default local image path + """ + brand_favicon_url = settings.FAVICON_URL + default_local_path = getattr(settings, 'FAVICON_PATH', 'images/favicon.ico') + favicon_url_from_site_config = configuration_helpers.get_value('favicon_path') + + if app_logs_enabled(): + log.info( + ("[Branding][get_favicon_url]: site_config:%s, brand_url:%s " + "default:%s"), + favicon_url_from_site_config, + brand_favicon_url, + default_local_path, + ) + + if favicon_url_from_site_config: + return staticfiles_storage.url(favicon_url_from_site_config) + + if brand_favicon_url: + return brand_favicon_url + + return staticfiles_storage.url(default_local_path) def get_tos_and_honor_code_url(): diff --git a/lms/djangoapps/branding/toggles.py b/lms/djangoapps/branding/toggles.py new file mode 100644 index 0000000000..b025af216a --- /dev/null +++ b/lms/djangoapps/branding/toggles.py @@ -0,0 +1,32 @@ +""" +Waffle flags for Branding app. +""" +from edx_toggles.toggles import WaffleFlag, WaffleFlagNamespace + + +WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='branding') +# Waffle flag for testing purpose only. When setting the flag in prod, +# make sure to have the following settings. Use "dwft_branding.enable_branding_logs=1" +# in the browser query to enable the flag. +# .. toggle_name: branding.enable_branding_logs +# .. toggle_everyone: unknown +# .. toggle_testing: True +# .. toggle_implementation: WaffleFlag +# .. toggle_default: False +# .. toggle_description: Supports testing for re-branding work. +# .. toggle_category: branding +# .. toggle_use_cases: open_edx +# .. toggle_creation_date: 2020-11-22 +# .. toggle_target_removal_date: 2021-01-01 +# .. toggle_warnings: n/a +# .. toggle_tickets: TNL-7695 +# .. toggle_status: supported +ENABLE_BRANDING_LOGS = WaffleFlag( + waffle_namespace=WAFFLE_FLAG_NAMESPACE, + flag_name='enable_branding_logs', +) + + +def app_logs_enabled(): + """Check if app logging is enabled. """ + return ENABLE_BRANDING_LOGS.is_enabled() diff --git a/lms/envs/common.py b/lms/envs/common.py index 2dcc99d26f..7dfd0fd638 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -4148,3 +4148,10 @@ MAX_BLOCKS_PER_CONTENT_LIBRARY = 1000 # COUNTRIES_FIRST = ['SA', 'BH', 'QA'] will display these countries on top of the list # https://github.com/SmileyChris/django-countries#show-certain-countries-first COUNTRIES_FIRST = [] + +################# Settings for brand logos. ################# +LOGO_URL = None +LOGO_URL_PNG = None +LOGO_TRADEMARK_URL = None +FAVICON_URL = None +DEFAULT_EMAIL_LOGO_URL = 'https://edx-cdn.org/v3/default/logo.png' diff --git a/lms/envs/production.py b/lms/envs/production.py index 578fac7bc2..2cb1d13608 100644 --- a/lms/envs/production.py +++ b/lms/envs/production.py @@ -975,3 +975,9 @@ COMPLETION_VIDEO_COMPLETE_PERCENTAGE = ENV_TOKENS.get('COMPLETION_VIDEO_COMPLETE COMPLETION_VIDEO_COMPLETE_PERCENTAGE) COMPLETION_VIDEO_COMPLETE_PERCENTAGE = ENV_TOKENS.get('COMPLETION_BY_VIEWING_DELAY_MS', COMPLETION_BY_VIEWING_DELAY_MS) + +################# Settings for brand logos. ################# +LOGO_URL = ENV_TOKENS.get('LOGO_URL', LOGO_URL) +LOGO_URL_PNG = ENV_TOKENS.get('LOGO_URL_PNG', LOGO_URL_PNG) +LOGO_TRADEMARK_URL = ENV_TOKENS.get('LOGO_TRADEMARK_URL', LOGO_TRADEMARK_URL) +FAVICON_URL = ENV_TOKENS.get('FAVICON_URL', FAVICON_URL) diff --git a/lms/static/sass/shared/_footer-edx.scss b/lms/static/sass/shared/_footer-edx.scss index e1ade87c0b..286ccfe4bd 100644 --- a/lms/static/sass/shared/_footer-edx.scss +++ b/lms/static/sass/shared/_footer-edx.scss @@ -159,6 +159,10 @@ footer#footer-edx-v3 { display: inline-flex; @include margin-left(5px); + + img { + height: $header-logo-height*1.05; + } } // To match the Pattern Library diff --git a/lms/static/sass/shared/_footer.scss b/lms/static/sass/shared/_footer.scss index 18ef6d6a7d..23b315e685 100644 --- a/lms/static/sass/shared/_footer.scss +++ b/lms/static/sass/shared/_footer.scss @@ -124,6 +124,10 @@ a { display: inline-block; + img { + height: $header-logo-height*1.05; + } + &:hover { border-bottom: 0; } diff --git a/lms/templates/main.html b/lms/templates/main.html index 14b02024c3..741a4092fd 100644 --- a/lms/templates/main.html +++ b/lms/templates/main.html @@ -82,8 +82,10 @@ from common.djangoapps.pipeline_mako import render_require_js_path_overrides % endif + <% favicon_url = branding_api.get_favicon_url() %> + + - <%static:css group='style-vendor'/> % if '/' in self.attr.main_css: diff --git a/openedx/core/djangoapps/ace_common/template_context.py b/openedx/core/djangoapps/ace_common/template_context.py index b569798a95..a1339e209f 100644 --- a/openedx/core/djangoapps/ace_common/template_context.py +++ b/openedx/core/djangoapps/ace_common/template_context.py @@ -16,6 +16,7 @@ def get_base_template_context(site): """ # When on LMS and a dashboard is available, use that as the dashboard url. # Otherwise, use the home url instead. + default_logo_url = getattr(settings, 'DEFAULT_EMAIL_LOGO_URL') try: dashboard_url = reverse('dashboard') except NoReverseMatch: @@ -37,4 +38,5 @@ def get_base_template_context(site): 'CONTACT_MAILING_ADDRESS', site=site, site_config_name='contact_mailing_address'), 'social_media_urls': get_config_value_from_site_or_settings('SOCIAL_MEDIA_FOOTER_URLS', site=site), 'mobile_store_urls': get_config_value_from_site_or_settings('MOBILE_STORE_URLS', site=site), + 'logo_url': getattr(settings, 'LOGO_URL_PNG', default_logo_url), } diff --git a/openedx/core/djangoapps/ace_common/templates/ace_common/edx_ace/common/base_body.html b/openedx/core/djangoapps/ace_common/templates/ace_common/edx_ace/common/base_body.html index 7130554dcf..ab792a7d3b 100644 --- a/openedx/core/djangoapps/ace_common/templates/ace_common/edx_ace/common/base_body.html +++ b/openedx/core/djangoapps/ace_common/templates/ace_common/edx_ace/common/base_body.html @@ -62,7 +62,7 @@