Server - Path blueprint fixes and moving code blueprint to fix RSS forward slash on url (#3054)

pull/3060/head
dgtlmoon 2025-03-25 22:57:15 +01:00 zatwierdzone przez GitHub
rodzic 5b97c29714
commit 302ef80d95
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
53 zmienionych plików z 290 dodań i 268 usunięć

Wyświetl plik

@ -138,7 +138,7 @@ def construct_blueprint(datastore: ChangeDetectionStore):
return send_from_directory(os.path.abspath(datastore.datastore_path), filename, as_attachment=True)
@login_optionally_required
@backups_blueprint.route("/", methods=['GET'])
@backups_blueprint.route("", methods=['GET'])
def index():
backups = find_backups()
output = render_template("overview.html",

Wyświetl plik

@ -27,7 +27,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid}))
if len(importer_handler.remaining_data) == 0:
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
else:
remaining_urls = importer_handler.remaining_data

Wyświetl plik

@ -20,13 +20,13 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q: PriorityQueue
datastore.data['watching'][uuid]['processor'] = 'restock_diff'
datastore.data['watching'][uuid].clear_watch()
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid}))
return redirect(url_for("index"))
return redirect(url_for("watchlist.index"))
@login_required
@price_data_follower_blueprint.route("/<string:uuid>/reject", methods=['GET'])
def reject(uuid):
datastore.data['watching'][uuid]['track_ldjson_price_data'] = PRICE_DATA_TRACK_REJECT
return redirect(url_for("index"))
return redirect(url_for("watchlist.index"))
return price_data_follower_blueprint

Wyświetl plik

@ -13,8 +13,7 @@ def construct_blueprint(datastore: ChangeDetectionStore):
# Import the login decorator if needed
# from changedetectionio.auth_decorator import login_optionally_required
@rss_blueprint.route("/", methods=['GET'])
@rss_blueprint.route("", methods=['GET'])
def feed():
now = time.time()
# Always requires token set

Wyświetl plik

@ -13,7 +13,7 @@ from changedetectionio.auth_decorator import login_optionally_required
def construct_blueprint(datastore: ChangeDetectionStore):
settings_blueprint = Blueprint('settings', __name__, template_folder="templates")
@settings_blueprint.route("/", methods=['GET', "POST"])
@settings_blueprint.route("", methods=['GET', "POST"])
@login_optionally_required
def settings_page():
from changedetectionio import forms
@ -74,7 +74,7 @@ def construct_blueprint(datastore: ChangeDetectionStore):
datastore.needs_write_urgent = True
flash("Password protection enabled.", 'notice')
flask_login.logout_user()
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
datastore.needs_write_urgent = True
flash("Settings updated.")

Wyświetl plik

@ -299,7 +299,7 @@ nav
<div id="actions">
<div class="pure-control-group">
{{ render_button(form.save_button) }}
<a href="{{url_for('index')}}" class="pure-button button-small button-cancel">Back</a>
<a href="{{url_for('watchlist.index')}}" class="pure-button button-small button-cancel">Back</a>
<a href="{{url_for('ui.clear_all_history')}}" class="pure-button button-small button-error">Clear Snapshot History</a>
</div>
</div>

Wyświetl plik

@ -47,7 +47,7 @@
<a class="link-mute state-{{'on' if tag.notification_muted else 'off'}}" href="{{url_for('tags.mute', uuid=tag.uuid)}}"><img src="{{url_for('static_content', group='images', filename='bell-off.svg')}}" alt="Mute notifications" title="Mute notifications" class="icon icon-mute" ></a>
</td>
<td>{{ "{:,}".format(tag_count[uuid]) if uuid in tag_count else 0 }}</td>
<td class="title-col inline"> <a href="{{url_for('index', tag=uuid) }}">{{ tag.title }}</a></td>
<td class="title-col inline"> <a href="{{url_for('watchlist.index', tag=uuid) }}">{{ tag.title }}</a></td>
<td>
<a class="pure-button pure-button-primary" href="{{ url_for('tags.form_tag_edit', uuid=uuid) }}">Edit</a>&nbsp;
<a class="pure-button pure-button-primary" href="{{ url_for('tags.delete', uuid=uuid) }}" title="Deletes and removes tag">Delete</a>

Wyświetl plik

@ -36,7 +36,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
else:
flash("Cleared snapshot history for watch {}".format(uuid))
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
@ui_blueprint.route("/clear_history", methods=['GET', 'POST'])
@login_optionally_required
@ -52,7 +52,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
else:
flash('Incorrect confirmation text.', 'error')
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
output = render_template("clear_all_history.html")
return output
@ -68,7 +68,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
continue
datastore.set_last_viewed(watch_uuid, int(time.time()))
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
@ui_blueprint.route("/delete", methods=['GET'])
@login_optionally_required
@ -77,7 +77,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
if uuid != 'all' and not uuid in datastore.data['watching'].keys():
flash('The watch by UUID {} does not exist.'.format(uuid), 'error')
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
# More for testing, possible to return the first/only
if uuid == 'first':
@ -85,7 +85,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
datastore.delete(uuid)
flash('Deleted.')
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
@ui_blueprint.route("/clone", methods=['GET'])
@login_optionally_required
@ -101,7 +101,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=5, item={'uuid': new_uuid}))
flash('Cloned.')
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
@ui_blueprint.route("/checknow", methods=['GET'])
@login_optionally_required
@ -143,7 +143,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
if i == 0:
flash("No watches available to recheck.")
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
@ui_blueprint.route("/form/checkbox-operations", methods=['POST'])
@login_optionally_required
@ -244,7 +244,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
flash(f"{len(uuids)} watches were tagged")
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
@ui_blueprint.route("/share-url/<string:uuid>", methods=['GET'])
@ -296,6 +296,6 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
logger.error(f"Error sharing -{str(e)}")
flash(f"Could not share, something went wrong while communicating with the share server - {str(e)}", 'error')
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
return ui_blueprint

Wyświetl plik

@ -32,14 +32,14 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
# More for testing, possible to return the first/only
if not datastore.data['watching'].keys():
flash("No watches to edit", "error")
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
if uuid == 'first':
uuid = list(datastore.data['watching'].keys()).pop()
if not uuid in datastore.data['watching']:
flash("No watch with the UUID %s found." % (uuid), "error")
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
switch_processor = request.args.get('switch_processor')
if switch_processor:
@ -66,7 +66,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
processor_classes = next((tpl for tpl in processors.find_processors() if tpl[1] == processor_name), None)
if not processor_classes:
flash(f"Cannot load the edit form for processor/plugin '{processor_classes[1]}', plugin missing?", 'error')
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
parent_module = processors.get_parent_module(processor_classes[0])
@ -207,7 +207,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
if request.args.get("next") and request.args.get("next") == 'diff':
return redirect(url_for('ui.ui_views.diff_history_page', uuid=uuid))
return redirect(url_for('index', tag=request.args.get("tag",'')))
return redirect(url_for('watchlist.index', tag=request.args.get("tag",'')))
else:
if request.method == 'POST' and not form.validate():

Wyświetl plik

@ -37,7 +37,7 @@
</div>
<br />
<div class="pure-control-group">
<a href="{{url_for('index')}}" class="pure-button button-cancel"
<a href="{{url_for('watchlist.index')}}" class="pure-button button-cancel"
>Cancel</a
>
</div>

Wyświetl plik

@ -26,7 +26,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
watch = datastore.data['watching'][uuid]
except KeyError:
flash("No history found for the specified link, bad link?", "error")
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
system_uses_webdriver = datastore.data['settings']['application']['fetch_backend'] == 'html_webdriver'
extra_stylesheets = [url_for('static_content', group='styles', filename='diff.css')]
@ -91,7 +91,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
watch = datastore.data['watching'][uuid]
except KeyError:
flash("No history found for the specified link, bad link?", "error")
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
# For submission of requesting an extract
extract_form = forms.extractDataForm(request.form)
@ -119,7 +119,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
if len(dates) < 2:
flash("Not enough saved change detection snapshots to produce a report.", "error")
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
# Save the current newest history as the most recently viewed
datastore.set_last_viewed(uuid, time.time())
@ -196,7 +196,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
if not form.validate():
for widget, l in form.errors.items():
flash(','.join(l), 'error')
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
url = request.form.get('url').strip()
if datastore.url_exists(url):
@ -215,6 +215,6 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': new_uuid}))
flash("Watch added.")
return redirect(url_for('index', tag=request.args.get('tag','')))
return redirect(url_for('watchlist.index', tag=request.args.get('tag','')))
return views_blueprint

Wyświetl plik

@ -0,0 +1,114 @@
import flask_login
import os
import time
import timeago
from flask import Blueprint, request, make_response, render_template, redirect, url_for, flash, session
from flask_login import current_user
from flask_paginate import Pagination, get_page_parameter
from changedetectionio import forms
from changedetectionio.store import ChangeDetectionStore
from changedetectionio.auth_decorator import login_optionally_required
from changedetectionio.strtobool import strtobool
def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData):
watchlist_blueprint = Blueprint('watchlist', __name__, template_folder="templates")
@watchlist_blueprint.route("/", methods=['GET'])
@login_optionally_required
def index():
active_tag_req = request.args.get('tag', '').lower().strip()
active_tag_uuid = active_tag = None
# Be sure limit_tag is a uuid
if active_tag_req:
for uuid, tag in datastore.data['settings']['application'].get('tags', {}).items():
if active_tag_req == tag.get('title', '').lower().strip() or active_tag_req == uuid:
active_tag = tag
active_tag_uuid = uuid
break
# Redirect for the old rss path which used the /?rss=true
if request.args.get('rss'):
return redirect(url_for('rss.feed', tag=active_tag_uuid))
op = request.args.get('op')
if op:
uuid = request.args.get('uuid')
if op == 'pause':
datastore.data['watching'][uuid].toggle_pause()
elif op == 'mute':
datastore.data['watching'][uuid].toggle_mute()
datastore.needs_write = True
return redirect(url_for('watchlist.index', tag = active_tag_uuid))
# Sort by last_changed and add the uuid which is usually the key..
sorted_watches = []
with_errors = request.args.get('with_errors') == "1"
errored_count = 0
search_q = request.args.get('q').strip().lower() if request.args.get('q') else False
for uuid, watch in datastore.data['watching'].items():
if with_errors and not watch.get('last_error'):
continue
if active_tag_uuid and not active_tag_uuid in watch['tags']:
continue
if watch.get('last_error'):
errored_count += 1
if search_q:
if (watch.get('title') and search_q in watch.get('title').lower()) or search_q in watch.get('url', '').lower():
sorted_watches.append(watch)
elif watch.get('last_error') and search_q in watch.get('last_error').lower():
sorted_watches.append(watch)
else:
sorted_watches.append(watch)
form = forms.quickWatchForm(request.form)
page = request.args.get(get_page_parameter(), type=int, default=1)
total_count = len(sorted_watches)
pagination = Pagination(page=page,
total=total_count,
per_page=datastore.data['settings']['application'].get('pager_size', 50), css_framework="semantic")
sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title'])
output = render_template(
"watch-overview.html",
# Don't link to hosting when we're on the hosting environment
active_tag=active_tag,
active_tag_uuid=active_tag_uuid,
app_rss_token=datastore.data['settings']['application'].get('rss_access_token'),
datastore=datastore,
errored_count=errored_count,
form=form,
guid=datastore.data['app_guid'],
has_proxies=datastore.proxy_list,
has_unviewed=datastore.has_unviewed,
hosted_sticky=os.getenv("SALTED_PASS", False) == False,
pagination=pagination,
queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
search_q=request.args.get('q','').strip(),
sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'),
sort_order=request.args.get('order') if request.args.get('order') else request.cookies.get('order'),
system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'),
tags=sorted_tags,
watches=sorted_watches
)
if session.get('share-link'):
del(session['share-link'])
resp = make_response(output)
# The template can run on cookie or url query info
if request.args.get('sort'):
resp.set_cookie('sort', request.args.get('sort'))
if request.args.get('order'):
resp.set_cookie('order', request.args.get('order'))
return resp
return watchlist_blueprint

Wyświetl plik

@ -46,12 +46,12 @@
{% endif %}
{% if search_q %}<div id="search-result-info">Searching "<strong><i>{{search_q}}</i></strong>"</div>{% endif %}
<div>
<a href="{{url_for('index')}}" class="pure-button button-tag {{'active' if not active_tag_uuid }}">All</a>
<a href="{{url_for('watchlist.index')}}" class="pure-button button-tag {{'active' if not active_tag_uuid }}">All</a>
<!-- tag list -->
{% for uuid, tag in tags %}
{% if tag != "" %}
<a href="{{url_for('index', tag=uuid) }}" class="pure-button button-tag {{'active' if active_tag_uuid == uuid }}">{{ tag.title }}</a>
<a href="{{url_for('watchlist.index', tag=uuid) }}" class="pure-button button-tag {{'active' if active_tag_uuid == uuid }}">{{ tag.title }}</a>
{% endif %}
{% endfor %}
</div>
@ -72,14 +72,14 @@
<tr>
{% set link_order = "desc" if sort_order == 'asc' else "asc" %}
{% set arrow_span = "" %}
<th><input style="vertical-align: middle" type="checkbox" id="check-all" > <a class="{{ 'active '+link_order if sort_attribute == 'date_created' else 'inactive' }}" href="{{url_for('index', sort='date_created', order=link_order, tag=active_tag_uuid)}}"># <span class='arrow {{link_order}}'></span></a></th>
<th><input style="vertical-align: middle" type="checkbox" id="check-all" > <a class="{{ 'active '+link_order if sort_attribute == 'date_created' else 'inactive' }}" href="{{url_for('watchlist.index', sort='date_created', order=link_order, tag=active_tag_uuid)}}"># <span class='arrow {{link_order}}'></span></a></th>
<th class="empty-cell"></th>
<th><a class="{{ 'active '+link_order if sort_attribute == 'label' else 'inactive' }}" href="{{url_for('index', sort='label', order=link_order, tag=active_tag_uuid)}}">Website <span class='arrow {{link_order}}'></span></a></th>
<th><a class="{{ 'active '+link_order if sort_attribute == 'label' else 'inactive' }}" href="{{url_for('watchlist.index', sort='label', order=link_order, tag=active_tag_uuid)}}">Website <span class='arrow {{link_order}}'></span></a></th>
{% if any_has_restock_price_processor %}
<th>Restock &amp; Price</th>
{% endif %}
<th><a class="{{ 'active '+link_order if sort_attribute == 'last_checked' else 'inactive' }}" href="{{url_for('index', sort='last_checked', order=link_order, tag=active_tag_uuid)}}"><span class="hide-on-mobile">Last</span> Checked <span class='arrow {{link_order}}'></span></a></th>
<th><a class="{{ 'active '+link_order if sort_attribute == 'last_changed' else 'inactive' }}" href="{{url_for('index', sort='last_changed', order=link_order, tag=active_tag_uuid)}}"><span class="hide-on-mobile">Last</span> Changed <span class='arrow {{link_order}}'></span></a></th>
<th><a class="{{ 'active '+link_order if sort_attribute == 'last_checked' else 'inactive' }}" href="{{url_for('watchlist.index', sort='last_checked', order=link_order, tag=active_tag_uuid)}}"><span class="hide-on-mobile">Last</span> Checked <span class='arrow {{link_order}}'></span></a></th>
<th><a class="{{ 'active '+link_order if sort_attribute == 'last_changed' else 'inactive' }}" href="{{url_for('watchlist.index', sort='last_changed', order=link_order, tag=active_tag_uuid)}}"><span class="hide-on-mobile">Last</span> Changed <span class='arrow {{link_order}}'></span></a></th>
<th class="empty-cell"></th>
</tr>
</thead>
@ -104,12 +104,12 @@
<td class="inline checkbox-uuid" ><input name="uuids" type="checkbox" value="{{ watch.uuid}} " > <span>{{ loop.index+pagination.skip }}</span></td>
<td class="inline watch-controls">
{% if not watch.paused %}
<a class="state-off" href="{{url_for('index', op='pause', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='pause.svg')}}" alt="Pause checks" title="Pause checks" class="icon icon-pause" ></a>
<a class="state-off" href="{{url_for('watchlist.index', op='pause', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='pause.svg')}}" alt="Pause checks" title="Pause checks" class="icon icon-pause" ></a>
{% else %}
<a class="state-on" href="{{url_for('index', op='pause', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='play.svg')}}" alt="UnPause checks" title="UnPause checks" class="icon icon-unpause" ></a>
<a class="state-on" href="{{url_for('watchlist.index', op='pause', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='play.svg')}}" alt="UnPause checks" title="UnPause checks" class="icon icon-unpause" ></a>
{% endif %}
{% set mute_label = 'UnMute notification' if watch.notification_muted else 'Mute notification' %}
<a class="link-mute state-{{'on' if watch.notification_muted else 'off'}}" href="{{url_for('index', op='mute', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='bell-off.svg')}}" alt="{{ mute_label }}" title="{{ mute_label }}" class="icon icon-mute" ></a>
<a class="link-mute state-{{'on' if watch.notification_muted else 'off'}}" href="{{url_for('watchlist.index', op='mute', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='bell-off.svg')}}" alt="{{ mute_label }}" title="{{ mute_label }}" class="icon icon-mute" ></a>
</td>
<td class="title-col inline">{{watch.title if watch.title is not none and watch.title|length > 0 else watch.url}}
<a class="external" target="_blank" rel="noopener" href="{{ watch.link.replace('source:','') }}"></a>
@ -210,7 +210,7 @@
<ul id="post-list-buttons">
{% if errored_count %}
<li>
<a href="{{url_for('index', with_errors=1, tag=request.args.get('tag')) }}" class="pure-button button-tag button-error ">With errors ({{ errored_count }})</a>
<a href="{{url_for('watchlist.index', with_errors=1, tag=request.args.get('tag')) }}" class="pure-button button-tag button-error ">With errors ({{ errored_count }})</a>
</li>
{% endif %}
{% if has_unviewed %}

Wyświetl plik

@ -229,7 +229,7 @@ def changedetection_app(config=None, datastore_o=None):
if has_password_enabled and not flask_login.current_user.is_authenticated:
# Permitted
if request.endpoint and 'static_content' in request.endpoint and request.view_args and request.view_args.get('group') == 'styles':
if request.endpoint and request.endpoint == 'static_content' and request.view_args and request.view_args.get('group') in ['styles', 'js', 'images', 'favicons']:
return None
# Permitted
elif request.endpoint and 'login' in request.endpoint:
@ -291,12 +291,12 @@ def changedetection_app(config=None, datastore_o=None):
@login_manager.unauthorized_handler
def unauthorized_handler():
flash("You must be logged in, please log in.", 'error')
return redirect(url_for('login', next=url_for('index')))
return redirect(url_for('login', next=url_for('watchlist.index')))
@app.route('/logout')
def logout():
flask_login.logout_user()
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
# https://github.com/pallets/flask/blob/93dd1709d05a1cf0e886df6223377bdab3b077fb/examples/tutorial/flaskr/__init__.py#L39
# You can divide up the stuff like this
@ -306,7 +306,7 @@ def changedetection_app(config=None, datastore_o=None):
if request.method == 'GET':
if flask_login.current_user.is_authenticated:
flash("Already logged in")
return redirect(url_for("index"))
return redirect(url_for("watchlist.index"))
output = render_template("login.html")
return output
@ -323,13 +323,13 @@ def changedetection_app(config=None, datastore_o=None):
# It's more reliable and safe to ignore the 'next' redirect
# When we used...
# next = request.args.get('next')
# return redirect(next or url_for('index'))
# return redirect(next or url_for('watchlist.index'))
# We would sometimes get login loop errors on sites hosted in sub-paths
# note for the future:
# if not is_safe_url(next):
# return flask.abort(400)
return redirect(url_for('index'))
return redirect(url_for('watchlist.index'))
else:
flash('Incorrect password', 'error')
@ -342,110 +342,8 @@ def changedetection_app(config=None, datastore_o=None):
if os.getenv('USE_X_SETTINGS') and 'X-Forwarded-Prefix' in request.headers:
app.config['REMEMBER_COOKIE_PATH'] = request.headers['X-Forwarded-Prefix']
app.config['SESSION_COOKIE_PATH'] = request.headers['X-Forwarded-Prefix']
return None
@app.route("/", methods=['GET'])
@login_optionally_required
def index():
global datastore
from changedetectionio import forms
active_tag_req = request.args.get('tag', '').lower().strip()
active_tag_uuid = active_tag = None
# Be sure limit_tag is a uuid
if active_tag_req:
for uuid, tag in datastore.data['settings']['application'].get('tags', {}).items():
if active_tag_req == tag.get('title', '').lower().strip() or active_tag_req == uuid:
active_tag = tag
active_tag_uuid = uuid
break
# Redirect for the old rss path which used the /?rss=true
if request.args.get('rss'):
return redirect(url_for('rss.feed', tag=active_tag_uuid))
op = request.args.get('op')
if op:
uuid = request.args.get('uuid')
if op == 'pause':
datastore.data['watching'][uuid].toggle_pause()
elif op == 'mute':
datastore.data['watching'][uuid].toggle_mute()
datastore.needs_write = True
return redirect(url_for('index', tag = active_tag_uuid))
# Sort by last_changed and add the uuid which is usually the key..
sorted_watches = []
with_errors = request.args.get('with_errors') == "1"
errored_count = 0
search_q = request.args.get('q').strip().lower() if request.args.get('q') else False
for uuid, watch in datastore.data['watching'].items():
if with_errors and not watch.get('last_error'):
continue
if active_tag_uuid and not active_tag_uuid in watch['tags']:
continue
if watch.get('last_error'):
errored_count += 1
if search_q:
if (watch.get('title') and search_q in watch.get('title').lower()) or search_q in watch.get('url', '').lower():
sorted_watches.append(watch)
elif watch.get('last_error') and search_q in watch.get('last_error').lower():
sorted_watches.append(watch)
else:
sorted_watches.append(watch)
form = forms.quickWatchForm(request.form)
page = request.args.get(get_page_parameter(), type=int, default=1)
total_count = len(sorted_watches)
pagination = Pagination(page=page,
total=total_count,
per_page=datastore.data['settings']['application'].get('pager_size', 50), css_framework="semantic")
sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title'])
output = render_template(
"watch-overview.html",
# Don't link to hosting when we're on the hosting environment
active_tag=active_tag,
active_tag_uuid=active_tag_uuid,
app_rss_token=datastore.data['settings']['application'].get('rss_access_token'),
datastore=datastore,
errored_count=errored_count,
form=form,
guid=datastore.data['app_guid'],
has_proxies=datastore.proxy_list,
has_unviewed=datastore.has_unviewed,
hosted_sticky=os.getenv("SALTED_PASS", False) == False,
pagination=pagination,
queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
search_q=request.args.get('q','').strip(),
sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'),
sort_order=request.args.get('order') if request.args.get('order') else request.cookies.get('order'),
system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'),
tags=sorted_tags,
watches=sorted_watches
)
if session.get('share-link'):
del(session['share-link'])
resp = make_response(output)
# The template can run on cookie or url query info
if request.args.get('sort'):
resp.set_cookie('sort', request.args.get('sort'))
if request.args.get('order'):
resp.set_cookie('order', request.args.get('order'))
return resp
@app.route("/static/<string:group>/<string:filename>", methods=['GET'])
def static_content(group, filename):
from flask import make_response
@ -533,10 +431,13 @@ def changedetection_app(config=None, datastore_o=None):
import changedetectionio.blueprint.rss as rss
app.register_blueprint(rss.construct_blueprint(datastore), url_prefix='/rss')
# watchlist UI buttons etc
import changedetectionio.blueprint.ui as ui
app.register_blueprint(ui.construct_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData))
import changedetectionio.blueprint.watchlist as watchlist
app.register_blueprint(watchlist.construct_blueprint(datastore=datastore, update_q=update_q, queuedWatchMetaData=queuedWatchMetaData), url_prefix='')
# @todo handle ctrl break
ticker_thread = threading.Thread(target=ticker_thread_check_time_launch_checks).start()

Wyświetl plik

@ -42,7 +42,7 @@
<a class="pure-menu-heading" href="https://changedetection.io" rel="noopener">
<strong>Change</strong>Detection.io</a>
{% else %}
<a class="pure-menu-heading" href="{{url_for('index')}}">
<a class="pure-menu-heading" href="{{url_for('watchlist.index')}}">
<strong>Change</strong>Detection.io</a>
{% endif %}
{% if current_diff_url %}

Wyświetl plik

@ -36,7 +36,7 @@ def test_select_custom(client, live_server, measure_memory_usage):
assert b"1 Imported" in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'Proxy Authentication Required' not in res.data
res = client.get(

Wyświetl plik

@ -83,14 +83,14 @@ def test_restock_detection(client, live_server, measure_memory_usage):
# Is it correctly show as NOT in stock?
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'not-in-stock' in res.data
# Is it correctly shown as in stock
set_back_in_stock_response()
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'not-in-stock' not in res.data
# We should have a notification
@ -107,6 +107,6 @@ def test_restock_detection(client, live_server, measure_memory_usage):
assert not os.path.isfile("test-datastore/notification.txt"), "No notification should have fired when it went OUT OF STOCK by default"
# BUT we should see that it correctly shows "not in stock"
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'not-in-stock' in res.data, "Correctly showing NOT IN STOCK in the list after it changed from IN STOCK"

Wyświetl plik

@ -1,4 +1,4 @@
from .util import live_server_setup
from .util import live_server_setup, wait_for_all_checks
from flask import url_for
import time
@ -44,7 +44,7 @@ def test_check_access_control(app, client, live_server):
assert b"Password protection enabled." in res.data
# Check we hit the login
res = c.get(url_for("index"), follow_redirects=True)
res = c.get(url_for("watchlist.index"), follow_redirects=True)
# Should be logged out
assert b"Login" in res.data
@ -52,6 +52,14 @@ def test_check_access_control(app, client, live_server):
res = c.get(url_for("ui.ui_views.diff_history_page", uuid="first"))
assert b'Random content' in res.data
# access to assets should work (check_authentication)
res = c.get(url_for('static_content', group='js', filename='jquery-3.6.0.min.js'))
assert res.status_code == 200
res = c.get(url_for('static_content', group='styles', filename='styles.css'))
assert res.status_code == 200
res = c.get(url_for('static_content', group='styles', filename='404-testetest.css'))
assert res.status_code == 404
# Check wrong password does not let us in
res = c.post(
url_for("login"),
@ -164,7 +172,7 @@ def test_check_access_control(app, client, live_server):
assert b"Password protection enabled." in res.data
# Check we hit the login
res = c.get(url_for("index"), follow_redirects=True)
res = c.get(url_for("watchlist.index"), follow_redirects=True)
# Should be logged out
assert b"Login" in res.data

Wyświetl plik

@ -72,7 +72,7 @@ def test_check_removed_line_contains_trigger(client, live_server, measure_memory
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
# The trigger line is REMOVED, this should trigger
@ -81,7 +81,7 @@ def test_check_removed_line_contains_trigger(client, live_server, measure_memory
# Check in the processor here what's going on, its triggering empty-reply and no change.
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
@ -90,14 +90,14 @@ def test_check_removed_line_contains_trigger(client, live_server, measure_memory
set_original(excluding=None)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
# Remove it again, and we should get a trigger
set_original(excluding='The golden line')
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
@ -157,14 +157,14 @@ def test_check_add_line_contains_trigger(client, live_server, measure_memory_usa
assert b'Queued 1 watch for rechecking.' in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
# The trigger line is ADDED, this should trigger
set_original(add_line='<p>Oh yes please</p>')
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data

Wyświetl plik

@ -383,7 +383,7 @@ def test_api_import(client, live_server, measure_memory_usage):
assert res.status_code == 200
assert len(res.json) == 2
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b"https://website1.com" in res.data
assert b"https://website2.com" in res.data

Wyświetl plik

@ -95,7 +95,7 @@ def test_check_ldjson_price_autodetect(client, live_server, measure_memory_usage
wait_for_all_checks(client)
# Should get a notice that it's available
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'ldjson-price-track-offer' in res.data
# Accept it
@ -105,7 +105,7 @@ def test_check_ldjson_price_autodetect(client, live_server, measure_memory_usage
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
# Offer should be gone
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'Embedded price data' not in res.data
assert b'tracking-ldjson-price-data' in res.data
@ -136,7 +136,7 @@ def test_check_ldjson_price_autodetect(client, live_server, measure_memory_usage
)
assert b"1 Imported" in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'ldjson-price-track-offer' not in res.data
##########################################################################################

Wyświetl plik

@ -39,7 +39,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'test-endpoint' in res.data
@ -75,7 +75,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
assert b'which has this one new line' in res.data
# Now something should be ready, indicated by having a 'unviewed' class
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
# #75, and it should be in the RSS feed
@ -112,7 +112,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'Mark all viewed' not in res.data
assert b'head title' not in res.data # Should not be present because this is off by default
@ -131,7 +131,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
assert b'Mark all viewed' in res.data
@ -151,7 +151,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
client.get(url_for("ui.clear_watch_history", uuid=uuid))
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'preview/' in res.data
#

Wyświetl plik

@ -107,7 +107,7 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data
@ -120,7 +120,7 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data
@ -129,7 +129,7 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
set_original_ignore_response()
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
@ -137,7 +137,7 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
set_modified_response_minus_block_text()
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data

Wyświetl plik

@ -114,7 +114,7 @@ def test_conditions_with_text_and_number(client, live_server):
wait_for_all_checks(client)
# 75 is > 20 and < 100 and contains "5"
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
@ -128,7 +128,7 @@ def test_conditions_with_text_and_number(client, live_server):
wait_for_all_checks(client)
# Should NOT be marked as having changes since not all conditions are met
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)

Wyświetl plik

@ -119,7 +119,7 @@ def test_check_markup_include_filters_restriction(client, live_server, measure_m
# It should have 'unviewed' still
# Because it should be looking at only that 'sametext' id
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
@ -218,7 +218,7 @@ def test_filter_is_empty_help_suggestion(client, live_server, measure_memory_usa
res = client.get(
url_for("index"),
url_for("watchlist.index"),
follow_redirects=True
)
@ -240,7 +240,7 @@ def test_filter_is_empty_help_suggestion(client, live_server, measure_memory_usa
wait_for_all_checks(client)
res = client.get(
url_for("index"),
url_for("watchlist.index"),
follow_redirects=True
)

Wyświetl plik

@ -204,7 +204,7 @@ def test_element_removal_full(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# There should not be an unviewed change, as changes should be removed
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b"unviewed" not in res.data
# Re #2752

Wyświetl plik

@ -32,7 +32,7 @@ def _runner_test_http_errors(client, live_server, http_code, expected_text):
# Give the thread time to pick it up
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
# no change
assert b'unviewed' not in res.data
assert bytes(expected_text.encode('utf-8')) in res.data
@ -78,7 +78,7 @@ def test_DNS_errors(client, live_server, measure_memory_usage):
# Give the thread time to pick it up
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
found_name_resolution_error = b"Temporary failure in name resolution" in res.data or b"Name or service not known" in res.data
assert found_name_resolution_error
# Should always record that we tried
@ -107,7 +107,7 @@ def test_low_level_errors_clear_correctly(client, live_server, measure_memory_us
wait_for_all_checks(client)
# We should see the DNS error
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
found_name_resolution_error = b"Temporary failure in name resolution" in res.data or b"Name or service not known" in res.data
assert found_name_resolution_error
@ -122,7 +122,7 @@ def test_low_level_errors_clear_correctly(client, live_server, measure_memory_us
# Now the error should be gone
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
found_name_resolution_error = b"Temporary failure in name resolution" in res.data or b"Name or service not known" in res.data
assert not found_name_resolution_error

Wyświetl plik

@ -103,7 +103,7 @@ def test_check_filter_multiline(client, live_server, measure_memory_usage):
assert b"Updated watch." in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
# Issue 1828
assert b'not at the start of the expression' not in res.data
@ -160,7 +160,7 @@ def test_check_filter_and_regex_extract(client, live_server, measure_memory_usag
# Give the thread time to pick it up
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
#issue 1828
assert b'not at the start of the expression' not in res.data
@ -174,7 +174,7 @@ def test_check_filter_and_regex_extract(client, live_server, measure_memory_usag
# It should have 'unviewed' still
# Because it should be looking at only that 'sametext' id
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
# Check HTML conversion detected and workd

Wyświetl plik

@ -113,7 +113,7 @@ def run_filter_test(client, live_server, content_filter):
checked += 1
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'Warning, no filters were found' in res.data
assert not os.path.isfile("test-datastore/notification.txt")
time.sleep(1)

Wyświetl plik

@ -77,7 +77,7 @@ def test_setup_group_tag(client, live_server, measure_memory_usage):
)
assert b"1 Imported" in res.data
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'import-tag' in res.data
assert b'extra-import-tag' in res.data
@ -90,7 +90,7 @@ def test_setup_group_tag(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'Warning, no filters were found' not in res.data
res = client.get(
@ -255,7 +255,7 @@ def test_limit_tag_ui(client, live_server, measure_memory_usage):
assert b"40 Imported" in res.data
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'test-tag' in res.data
# All should be here
@ -263,7 +263,7 @@ def test_limit_tag_ui(client, live_server, measure_memory_usage):
tag_uuid = get_UUID_for_tag_name(client, name="test-tag")
res = client.get(url_for("index", tag=tag_uuid))
res = client.get(url_for("watchlist.index", tag=tag_uuid))
# Just a subset should be here
assert b'test-tag' in res.data
@ -284,7 +284,7 @@ def test_clone_tag_on_import(client, live_server, measure_memory_usage):
assert b"1 Imported" in res.data
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'test-tag' in res.data
assert b'another-tag' in res.data
@ -311,7 +311,7 @@ def test_clone_tag_on_quickwatchform_add(client, live_server, measure_memory_usa
assert b"Watch added" in res.data
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'test-tag' in res.data
assert b'another-tag' in res.data

Wyświetl plik

@ -127,7 +127,7 @@ def test_check_ignore_text_functionality(client, live_server, measure_memory_usa
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data
@ -140,7 +140,7 @@ def test_check_ignore_text_functionality(client, live_server, measure_memory_usa
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data
@ -151,7 +151,7 @@ def test_check_ignore_text_functionality(client, live_server, measure_memory_usa
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
res = client.get(url_for("ui.ui_views.preview_page", uuid="first"))
@ -214,7 +214,7 @@ def test_check_global_ignore_text_functionality(client, live_server, measure_mem
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class), adding random ignore text should not cause a change
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data
#####
@ -229,7 +229,7 @@ def test_check_global_ignore_text_functionality(client, live_server, measure_mem
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data
@ -238,7 +238,7 @@ def test_check_global_ignore_text_functionality(client, live_server, measure_mem
set_modified_original_ignore_response()
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)

Wyświetl plik

@ -114,7 +114,7 @@ def test_render_anchor_tag_content_true(client, live_server, measure_memory_usag
# since the link has changed, and we chose to render anchor tag content,
# we should detect a change (new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b"unviewed" in res.data
assert b"/test-endpoint" in res.data

Wyświetl plik

@ -79,7 +79,7 @@ def test_normal_page_check_works_with_ignore_status_code(client, live_server, me
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
assert b'/test-endpoint' in res.data
@ -127,6 +127,6 @@ def test_403_page_check_works_with_ignore_status_code(client, live_server, measu
# It should have 'unviewed' still
# Because it should be looking at only that 'sametext' id
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data

Wyświetl plik

@ -91,6 +91,6 @@ def test_check_ignore_whitespace(client, live_server, measure_memory_usage):
time.sleep(sleep_time_for_fetch_thread)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data

Wyświetl plik

@ -31,8 +31,8 @@ https://example.com tag1, other tag"""
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
# Clear flask alerts
res = client.get( url_for("index"))
res = client.get( url_for("index"))
res = client.get( url_for("watchlist.index"))
res = client.get( url_for("watchlist.index"))
def xtest_import_skip_url(client, live_server, measure_memory_usage):
@ -55,7 +55,7 @@ def xtest_import_skip_url(client, live_server, measure_memory_usage):
assert b"1 Skipped" in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
# Clear flask alerts
res = client.get( url_for("index"))
res = client.get( url_for("watchlist.index"))
def test_import_distillio(client, live_server, measure_memory_usage):
@ -113,7 +113,7 @@ def test_import_distillio(client, live_server, measure_memory_usage):
assert b"xpath:(//div[@id=&#39;App&#39;]/div[contains(@class,&#39;flex&#39;)]/main[contains(@class,&#39;relative&#39;)]/section[contains(@class,&#39;relative&#39;)]/div[@class=&#39;container&#39;]/div[contains(@class,&#39;flex&#39;)]/div[contains(@class,&#39;w-full&#39;)])[1]" in res.data
# did the tags work?
res = client.get( url_for("index"))
res = client.get( url_for("watchlist.index"))
# check tags
assert b"nice stuff" in res.data
@ -121,7 +121,7 @@ def test_import_distillio(client, live_server, measure_memory_usage):
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
# Clear flask alerts
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
def test_import_custom_xlsx(client, live_server, measure_memory_usage):
"""Test can upload a excel spreadsheet and the watches are created correctly"""
@ -156,7 +156,7 @@ def test_import_custom_xlsx(client, live_server, measure_memory_usage):
assert b'Error processing row number 1' in res.data
res = client.get(
url_for("index")
url_for("watchlist.index")
)
assert b'Somesite results ABC' in res.data
@ -194,7 +194,7 @@ def test_import_watchete_xlsx(client, live_server, measure_memory_usage):
assert b'4 imported from Wachete .xlsx' in res.data
res = client.get(
url_for("index")
url_for("watchlist.index")
)
assert b'Somesite results ABC' in res.data

Wyświetl plik

@ -52,7 +52,7 @@ def test_jinja2_security_url_query(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'is invalid and cannot be used' in res.data
# Some of the spewed output from the subclasses
assert b'dict_values' not in res.data

Wyświetl plik

@ -281,7 +281,7 @@ def check_json_filter(json_filter, client, live_server):
wait_for_all_checks(client)
# It should have 'unviewed' still
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
# Should not see this, because its not in the JSONPath we entered
@ -417,7 +417,7 @@ def check_json_ext_filter(json_filter, client, live_server):
wait_for_all_checks(client)
# It should have 'unviewed'
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
res = client.get(url_for("ui.ui_views.diff_history_page", uuid="first"))
@ -455,7 +455,7 @@ def test_ignore_json_order(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
# Just to be sure it still works
@ -466,7 +466,7 @@ def test_ignore_json_order(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
@ -488,7 +488,7 @@ def test_correct_header_detect(client, live_server, measure_memory_usage):
)
assert b"1 Imported" in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
# Fixed in #1593
assert b'No parsable JSON found in this document' not in res.data

Wyświetl plik

@ -41,7 +41,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
@ -63,7 +63,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
uuid = next(iter(live_server.app.config['DATASTORE'].data['watching']))
@ -93,7 +93,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
client.get(url_for("ui.mark_all_viewed"), follow_redirects=True)
@ -105,7 +105,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
assert watch.last_changed == watch['last_checked']
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data # A change should have registered because empty_pages_are_a_change is ON
assert b'fetch-error' not in res.data

Wyświetl plik

@ -139,7 +139,7 @@ def test_check_notification(client, live_server, measure_memory_usage):
time.sleep(3)
# Check no errors were recorded
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'notification-error' not in res.data

Wyświetl plik

@ -46,7 +46,7 @@ def test_check_notification_error_handling(client, live_server, measure_memory_u
logging.debug("Fetching watch overview....")
res = client.get(
url_for("index"))
url_for("watchlist.index"))
if bytes("Notification error detected".encode('utf-8')) in res.data:
found=True

Wyświetl plik

@ -50,7 +50,7 @@ def test_fetch_pdf(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# Now something should be ready, indicated by having a 'unviewed' class
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
# The original checksum should be not be here anymore (cdio adds it to the bottom of the text)

Wyświetl plik

@ -48,7 +48,7 @@ def test_fetch_pdf(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# Now something should be ready, indicated by having a 'unviewed' class
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
# The original checksum should be not be here anymore (cdio adds it to the bottom of the text)

Wyświetl plik

@ -64,7 +64,7 @@ def test_restock_itemprop_basic(client, live_server):
follow_redirects=True
)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'more than one price detected' not in res.data
assert b'has-restock-info' in res.data
assert b' in-stock' in res.data
@ -81,7 +81,7 @@ def test_restock_itemprop_basic(client, live_server):
follow_redirects=True
)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'has-restock-info not-in-stock' in res.data
@ -103,14 +103,14 @@ def test_itemprop_price_change(client, live_server):
# A change in price, should trigger a change by default
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'190.95' in res.data
# basic price change, look for notification
set_original_response(props_markup=instock_props[0], price='180.45')
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'180.45' in res.data
assert b'unviewed' in res.data
client.get(url_for("ui.mark_all_viewed"), follow_redirects=True)
@ -125,7 +125,7 @@ def test_itemprop_price_change(client, live_server):
assert b"Updated watch." in res.data
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'120.45' in res.data
assert b'unviewed' not in res.data
@ -170,7 +170,7 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
set_original_response(props_markup=instock_props[0], price='1000.45')
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'more than one price detected' not in res.data
# BUT the new price should show, even tho its within limits
@ -183,7 +183,7 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'890.45' in res.data
assert b'unviewed' in res.data
@ -195,7 +195,7 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'820.45' in res.data
assert b'unviewed' in res.data
client.get(url_for("ui.mark_all_viewed"))
@ -204,7 +204,7 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
set_original_response(props_markup=instock_props[0], price='1890.45')
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
# Depending on the LOCALE it may be either of these (generally for US/default/etc)
assert b'1,890.45' in res.data or b'1890.45' in res.data
assert b'unviewed' in res.data
@ -288,7 +288,7 @@ def test_itemprop_percent_threshold(client, live_server):
set_original_response(props_markup=instock_props[0], price='960.45')
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'960.45' in res.data
assert b'unviewed' not in res.data
@ -296,7 +296,7 @@ def test_itemprop_percent_threshold(client, live_server):
set_original_response(props_markup=instock_props[0], price='1960.45')
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'1,960.45' or b'1960.45' in res.data #depending on locale
assert b'unviewed' in res.data
@ -306,7 +306,7 @@ def test_itemprop_percent_threshold(client, live_server):
set_original_response(props_markup=instock_props[0], price='1950.45')
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'1,950.45' or b'1950.45' in res.data #depending on locale
assert b'unviewed' not in res.data
@ -403,7 +403,7 @@ def test_data_sanity(client, live_server):
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'950.95' in res.data
# Check the restock model object doesnt store the value by mistake and used in a new one
@ -413,7 +413,7 @@ def test_data_sanity(client, live_server):
follow_redirects=True
)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert str(res.data.decode()).count("950.95") == 1, "Price should only show once (for the watch added, no other watches yet)"
## different test, check the edit page works on an empty request result
@ -455,6 +455,6 @@ def test_special_prop_examples(client, live_server):
follow_redirects=True
)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'ception' not in res.data
assert b'155.55' in res.data

Wyświetl plik

@ -20,7 +20,7 @@ def test_basic_search(client, live_server, measure_memory_usage):
assert b"2 Imported" in res.data
# By URL
res = client.get(url_for("index") + "?q=first-res")
res = client.get(url_for("watchlist.index") + "?q=first-res")
assert urls[0].encode('utf-8') in res.data
assert urls[1].encode('utf-8') not in res.data
@ -33,7 +33,7 @@ def test_basic_search(client, live_server, measure_memory_usage):
)
assert b"Updated watch." in res.data
res = client.get(url_for("index") + "?q=xxx-title")
res = client.get(url_for("watchlist.index") + "?q=xxx-title")
assert urls[0].encode('utf-8') in res.data
assert urls[1].encode('utf-8') not in res.data
@ -54,7 +54,7 @@ def test_search_in_tag_limit(client, live_server, measure_memory_usage):
# By URL
res = client.get(url_for("index") + "?q=first-res")
res = client.get(url_for("watchlist.index") + "?q=first-res")
# Split because of the import tag separation
assert urls[0].split(' ')[0].encode('utf-8') in res.data, urls[0].encode('utf-8')
assert urls[1].split(' ')[0].encode('utf-8') not in res.data, urls[0].encode('utf-8')
@ -68,7 +68,7 @@ def test_search_in_tag_limit(client, live_server, measure_memory_usage):
)
assert b"Updated watch." in res.data
res = client.get(url_for("index") + "?q=xxx-title")
res = client.get(url_for("watchlist.index") + "?q=xxx-title")
assert urls[0].split(' ')[0].encode('utf-8') in res.data, urls[0].encode('utf-8')
assert urls[1].split(' ')[0].encode('utf-8') not in res.data, urls[0].encode('utf-8')

Wyświetl plik

@ -67,7 +67,7 @@ def _runner_test_various_file_slash(client, file_uri):
follow_redirects=True
)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
substrings = [b"URLs with hostname components are not permitted", b"No connection adapters were found for"]

Wyświetl plik

@ -76,5 +76,5 @@ def test_share_watch(client, live_server, measure_memory_usage):
assert bytes(include_filters.encode('utf-8')) in res.data
# Check it saved the URL
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert bytes(test_url.encode('utf-8')) in res.data

Wyświetl plik

@ -45,7 +45,7 @@ def test_check_basic_change_detection_functionality_source(client, live_server,
wait_for_all_checks(client)
# Now something should be ready, indicated by having a 'unviewed' class
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
res = client.get(

Wyświetl plik

@ -104,7 +104,7 @@ def test_trigger_functionality(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data
@ -116,7 +116,7 @@ def test_trigger_functionality(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
# Now set the content which contains the trigger text
@ -124,7 +124,7 @@ def test_trigger_functionality(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
# https://github.com/dgtlmoon/changedetection.io/issues/616

Wyświetl plik

@ -41,7 +41,7 @@ def test_trigger_regex_functionality(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# It should report nothing found (just a new one shouldnt have anything)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
### test regex
@ -63,7 +63,7 @@ def test_trigger_regex_functionality(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# It should report nothing found (nothing should match the regex)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
with open("test-datastore/endpoint-content.txt", "w") as f:
@ -71,7 +71,7 @@ def test_trigger_regex_functionality(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
# Cleanup everything

Wyświetl plik

@ -67,7 +67,7 @@ def test_trigger_regex_functionality_with_filter(client, live_server, measure_me
time.sleep(sleep_time_for_fetch_thread)
# It should report nothing found (nothing should match the regex and filter)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
# now this should trigger something
@ -76,7 +76,7 @@ def test_trigger_regex_functionality_with_filter(client, live_server, measure_me
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
time.sleep(sleep_time_for_fetch_thread)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
# Cleanup everything

Wyświetl plik

@ -108,14 +108,14 @@ def test_unique_lines_functionality(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# It should report nothing found (no new 'unviewed' class)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
# Now set the content which contains the new text and re-ordered existing text
set_modified_with_trigger_text_response()
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
assert b'Deleted' in res.data
@ -153,7 +153,7 @@ def test_sort_lines_functionality(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
# Should be a change registered
assert b'unviewed' in res.data

Wyświetl plik

@ -98,7 +98,7 @@ def test_check_xpath_filter_utf8(client, live_server, measure_memory_usage):
)
assert b"Updated watch." in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'Unicode strings with encoding declaration are not supported.' not in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
assert b'Deleted' in res.data
@ -152,7 +152,7 @@ def test_check_xpath_text_function_utf8(client, live_server, measure_memory_usag
)
assert b"Updated watch." in res.data
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'Unicode strings with encoding declaration are not supported.' not in res.data
# The service should echo back the request headers
@ -208,7 +208,7 @@ def test_check_markup_xpath_filter_restriction(client, live_server, measure_memo
# Give the thread time to pick it up
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'unviewed' not in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
assert b'Deleted' in res.data
@ -305,7 +305,7 @@ def test_xpath1_lxml(client, live_server, measure_memory_usage):
##### #2312
wait_for_all_checks(client)
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'_ElementStringResult' not in res.data # tested with 5.1.1 when it was removed and 5.1.0
assert b'Exception' not in res.data
res = client.get(
@ -419,7 +419,7 @@ def test_various_rules(client, live_server, measure_memory_usage):
)
wait_for_all_checks(client)
assert b"Updated watch." in res.data
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
assert b'fetch-error' not in res.data, f"Should not see errors after '{r} filter"
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)

Wyświetl plik

@ -108,7 +108,7 @@ def get_UUID_for_tag_name(client, name):
def extract_rss_token_from_UI(client):
import re
res = client.get(
url_for("index"),
url_for("watchlist.index"),
)
m = re.search('token=(.+?)"', str(res.data))
token_key = m.group(1)
@ -118,7 +118,7 @@ def extract_rss_token_from_UI(client):
def extract_UUID_from_client(client):
import re
res = client.get(
url_for("index"),
url_for("watchlist.index"),
)
# <span id="api-key">{{api_key}}</span>
@ -133,7 +133,7 @@ def wait_for_all_checks(client):
# because sub-second rechecks are problematic in testing, use lots of delays
time.sleep(1)
while attempt < 60:
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
if not b'Checking now' in res.data:
break
logging.getLogger().info("Waiting for watch-list to not say 'Checking now'.. {}".format(attempt))
@ -306,7 +306,7 @@ def get_index(client):
print(f"Called by: {caller_name}, Line: {caller_line}")
res = client.get(url_for("index"))
res = client.get(url_for("watchlist.index"))
with open(f"test-datastore/index-{caller_name}-{caller_line}.html", 'wb') as f:
f.write(res.data)