Configurable BASE_URL (#228)
Re #152 ability to over-ride env var BASE_URL, with UI+tests
This commit is contained in:
@@ -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,8 +64,12 @@ 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>
|
||||||
|
<fieldset>
|
||||||
|
<div class="field-group">
|
||||||
{{ render_notifications_field(form) }}
|
{{ render_notifications_field(form) }}
|
||||||
</div>
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane-inner" id="filters">
|
<div class="tab-pane-inner" id="filters">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|||||||
@@ -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,8 +49,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane-inner" id="notifications">
|
<div class="tab-pane-inner" id="notifications">
|
||||||
|
<fieldset>
|
||||||
|
<div class="field-group">
|
||||||
{{ render_notifications_field(form) }}
|
{{ render_notifications_field(form) }}
|
||||||
</div>
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane-inner" id="fetching">
|
<div class="tab-pane-inner" id="fetching">
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user