Configurable BASE_URL (#228)

Re #152 ability to over-ride env var BASE_URL, with UI+tests
pull/245/head
dgtlmoon 3 years ago committed by GitHub
parent 2c71f577e0
commit 95e39aa727
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -497,6 +497,7 @@ def changedetection_app(config=None, datastore_o=None):
form.fetch_backend.data = datastore.data['settings']['application']['fetch_backend'] form.fetch_backend.data = datastore.data['settings']['application']['fetch_backend']
form.notification_title.data = datastore.data['settings']['application']['notification_title'] form.notification_title.data = datastore.data['settings']['application']['notification_title']
form.notification_body.data = datastore.data['settings']['application']['notification_body'] form.notification_body.data = datastore.data['settings']['application']['notification_body']
form.base_url.data = datastore.data['settings']['application']['base_url']
# Password unset is a GET # Password unset is a GET
if request.values.get('removepassword') == 'yes': if request.values.get('removepassword') == 'yes':
@ -514,9 +515,8 @@ def changedetection_app(config=None, datastore_o=None):
datastore.data['settings']['application']['fetch_backend'] = form.fetch_backend.data datastore.data['settings']['application']['fetch_backend'] = form.fetch_backend.data
datastore.data['settings']['application']['notification_title'] = form.notification_title.data datastore.data['settings']['application']['notification_title'] = form.notification_title.data
datastore.data['settings']['application']['notification_body'] = form.notification_body.data datastore.data['settings']['application']['notification_body'] = form.notification_body.data
datastore.data['settings']['application']['notification_urls'] = form.notification_urls.data datastore.data['settings']['application']['notification_urls'] = form.notification_urls.data
datastore.needs_write = True datastore.data['settings']['application']['base_url'] = form.base_url.data
if form.trigger_check.data and len(form.notification_urls.data): if form.trigger_check.data and len(form.notification_urls.data):
n_object = {'watch_url': "Test from changedetection.io!", n_object = {'watch_url': "Test from changedetection.io!",
@ -533,14 +533,13 @@ def changedetection_app(config=None, datastore_o=None):
flask_login.logout_user() flask_login.logout_user()
return redirect(url_for('index')) return redirect(url_for('index'))
datastore.needs_write = True
flash("Settings updated.") flash("Settings updated.")
if request.method == 'POST' and not form.validate(): if request.method == 'POST' and not form.validate():
flash("An error occurred, please see below.", "error") flash("An error occurred, please see below.", "error")
# Same as notification.py output = render_template("settings.html", form=form)
base_url = os.getenv('BASE_URL', '').strip('"')
output = render_template("settings.html", form=form, base_url=base_url)
return output return output

@ -223,6 +223,7 @@ class watchForm(commonSettingsForm):
class globalSettingsForm(commonSettingsForm): class globalSettingsForm(commonSettingsForm):
password = SaltyPasswordField() password = SaltyPasswordField()
minutes_between_check = html5.IntegerField('Maximum time in minutes until recheck', minutes_between_check = html5.IntegerField('Maximum time in minutes until recheck',
[validators.NumberRange(min=1)]) [validators.NumberRange(min=1)])
extract_title_as_title = BooleanField('Extract <title> from document and use as watch title')
base_url = StringField('Base URL', validators=[validators.Optional()])

@ -57,7 +57,8 @@ def create_notification_parameters(n_object, datastore):
watch_tag = '' watch_tag = ''
# Create URLs to customise the notification with # Create URLs to customise the notification with
base_url = os.getenv('BASE_URL', '').strip('"') base_url = datastore.data['settings']['application']['base_url']
watch_url = n_object['watch_url'] watch_url = n_object['watch_url']
# Re #148 - Some people have just {base_url} in the body or title, but this may break some notification services # Re #148 - Some people have just {base_url} in the body or title, but this may break some notification services

@ -9,11 +9,15 @@
# exit when any command fails # exit when any command fails
set -e set -e
# Re #65 - Ability to include a link back to the installation, in the notification.
export BASE_URL="https://foobar.com"
find tests/test_*py -type f|while read test_name find tests/test_*py -type f|while read test_name
do do
echo "TEST RUNNING $test_name" echo "TEST RUNNING $test_name"
pytest $test_name pytest $test_name
done done
# Now re-run some tests with BASE_URL enabled
# Re #65 - Ability to include a link back to the installation, in the notification.
export BASE_URL="https://really-unique-domain.io"
pytest tests/test_notification.py

@ -7,7 +7,7 @@ from copy import deepcopy
import logging import logging
import time import time
import threading import threading
import os
# Is there an existing library to ensure some data store (JSON etc) is in sync with CRUD methods? # Is there an existing library to ensure some data store (JSON etc) is in sync with CRUD methods?
# Open a github issue if you know something :) # Open a github issue if you know something :)
@ -38,6 +38,7 @@ class ChangeDetectionStore:
}, },
'application': { 'application': {
'password': False, 'password': False,
'base_url' : None,
'extract_title_as_title': False, 'extract_title_as_title': False,
'fetch_backend': 'html_requests', 'fetch_backend': 'html_requests',
'notification_urls': [], # Apprise URL list 'notification_urls': [], # Apprise URL list
@ -197,13 +198,15 @@ class ChangeDetectionStore:
has_unviewed = True has_unviewed = True
# #106 - Be sure this is None on empty string, False, None, etc # #106 - Be sure this is None on empty string, False, None, etc
if not self.__data['watching'][uuid]['title']:
self.__data['watching'][uuid]['title'] = None
# Default var for fetch_backend # Default var for fetch_backend
if not self.__data['watching'][uuid]['fetch_backend']: if not self.__data['watching'][uuid]['fetch_backend']:
self.__data['watching'][uuid]['fetch_backend'] = self.__data['settings']['application']['fetch_backend'] self.__data['watching'][uuid]['fetch_backend'] = self.__data['settings']['application']['fetch_backend']
# Re #152, Return env base_url if not overriden, @todo also prefer the proxy pass url
env_base_url = os.getenv('BASE_URL','')
if self.__data['settings']['application']['base_url'] is None and len(env_base_url) >0:
self.__data['settings']['application']['base_url'] = env_base_url.strip('" ')
self.__data['has_unviewed'] = has_unviewed self.__data['has_unviewed'] = has_unviewed
return self.__data return self.__data

@ -3,9 +3,6 @@
{% macro render_notifications_field(form) %} {% macro render_notifications_field(form) %}
<fieldset>
<div class="field-group">
<div class="pure-control-group"> <div class="pure-control-group">
{{ render_field(form.notification_urls, rows=5, placeholder="Examples: {{ render_field(form.notification_urls, rows=5, placeholder="Examples:
Gitter - gitter://token/room Gitter - gitter://token/room
@ -84,7 +81,4 @@
<div class="pure-control-group"> <div class="pure-control-group">
{{ render_field(form.trigger_check) }} {{ render_field(form.trigger_check) }}
</div> </div>
</div>
</fieldset>
{% endmacro %} {% endmacro %}

@ -64,7 +64,11 @@ User-Agent: wonderbra 1.0") }}
<div class="tab-pane-inner" id="notifications"> <div class="tab-pane-inner" id="notifications">
<strong>Note: <i>These settings override the global settings.</i></strong> <strong>Note: <i>These settings override the global settings.</i></strong>
{{ render_notifications_field(form) }} <fieldset>
<div class="field-group">
{{ render_notifications_field(form) }}
</div>
</fieldset>
</div> </div>
<div class="tab-pane-inner" id="filters"> <div class="tab-pane-inner" id="filters">

@ -32,6 +32,15 @@
<span class="pure-form-message-inline">Password protection for your changedetection.io application.</span> <span class="pure-form-message-inline">Password protection for your changedetection.io application.</span>
{% endif %} {% endif %}
</div> </div>
<div class="pure-control-group">
{{ render_field(form.base_url, placeholder="http://yoursite.com:5000/",
class="m-d") }}
<span class="pure-form-message-inline">
Base URL used for the {base_url} token in notifications, default value is the ENV var 'base_url',
<a href="https://github.com/dgtlmoon/changedetection.io/wiki/Configurable-BASE_URL-setting">read more here</a>.
</span>
</div>
<div class="pure-control-group"> <div class="pure-control-group">
{{ render_field(form.extract_title_as_title) }} {{ render_field(form.extract_title_as_title) }}
<span class="pure-form-message-inline">Note: This will automatically apply to all existing watches.</span> <span class="pure-form-message-inline">Note: This will automatically apply to all existing watches.</span>
@ -40,7 +49,11 @@
</div> </div>
<div class="tab-pane-inner" id="notifications"> <div class="tab-pane-inner" id="notifications">
{{ render_notifications_field(form) }} <fieldset>
<div class="field-group">
{{ render_notifications_field(form) }}
</div>
</fieldset>
</div> </div>
<div class="tab-pane-inner" id="fetching"> <div class="tab-pane-inner" id="fetching">

@ -36,11 +36,8 @@ def app(request):
except FileExistsError: except FileExistsError:
pass pass
# Enable a BASE_URL for notifications to work (so we can look for diff/ etc URLs)
os.environ["BASE_URL"] = "http://mysite.com/"
cleanup(datastore_path) cleanup(datastore_path)
app_config = {'datastore_path': datastore_path} app_config = {'datastore_path': datastore_path}
cleanup(app_config['datastore_path']) cleanup(app_config['datastore_path'])
datastore = store.ChangeDetectionStore(datastore_path=app_config['datastore_path'], include_default_watches=False) datastore = store.ChangeDetectionStore(datastore_path=app_config['datastore_path'], include_default_watches=False)

@ -3,6 +3,7 @@ import time
import re import re
from flask import url_for from flask import url_for
from . util import set_original_response, set_modified_response, live_server_setup from . util import set_original_response, set_modified_response, live_server_setup
import logging
# Hard to just add more live server URLs when one test is already running (I think) # Hard to just add more live server URLs when one test is already running (I think)
# So we add our test here (was in a different file) # So we add our test here (was in a different file)
@ -14,8 +15,16 @@ def test_check_notification(client, live_server):
# Give the endpoint time to spin up # Give the endpoint time to spin up
time.sleep(3) time.sleep(3)
# re #242 - when you edited an existing new entry, it would not correctly show the notification settings # When test mode is in BASE_URL env mode, we should see this already configured
env_base_url = os.getenv('BASE_URL', '').strip()
if len(env_base_url):
logging.debug(">>> BASE_URL enabled, looking for %s", env_base_url)
res = client.get(url_for("settings_page"))
assert bytes(env_base_url.encode('utf-8')) in res.data
else:
logging.debug(">>> SKIPPING BASE_URL check")
# re #242 - when you edited an existing new entry, it would not correctly show the notification settings
# Add our URL to the import page # Add our URL to the import page
test_url = url_for('test_endpoint', _external=True) test_url = url_for('test_endpoint', _external=True)
res = client.post( res = client.post(
@ -104,9 +113,12 @@ def test_check_notification(client, live_server):
assert test_url in notification_submission assert test_url in notification_submission
# Re #65 - did we see our foobar.com BASE_URL ? if env_base_url:
#assert bytes("https://foobar.com".encode('utf-8')) in notification_submission # Re #65 - did we see our BASE_URl ?
logging.debug (">>> BASE_URL checking in notification: %s", env_base_url)
assert env_base_url in notification_submission
else:
logging.debug(">>> Skipping BASE_URL check")
## Now configure something clever, we go into custom config (non-default) mode, this is returned by the endpoint ## Now configure something clever, we go into custom config (non-default) mode, this is returned by the endpoint
with open("test-datastore/endpoint-content.txt", "w") as f: with open("test-datastore/endpoint-content.txt", "w") as f:

Loading…
Cancel
Save