Skip to content

Commit 302ef80

Browse files
authored
Server - Path blueprint fixes and moving code blueprint to fix RSS forward slash on url (#3054)
1 parent 5b97c29 commit 302ef80

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+290
-268
lines changed

changedetectionio/blueprint/backups/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def download_backup(filename):
138138
return send_from_directory(os.path.abspath(datastore.datastore_path), filename, as_attachment=True)
139139

140140
@login_optionally_required
141-
@backups_blueprint.route("/", methods=['GET'])
141+
@backups_blueprint.route("", methods=['GET'])
142142
def index():
143143
backups = find_backups()
144144
output = render_template("overview.html",

changedetectionio/blueprint/imports/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def import_page():
2727
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid}))
2828

2929
if len(importer_handler.remaining_data) == 0:
30-
return redirect(url_for('index'))
30+
return redirect(url_for('watchlist.index'))
3131
else:
3232
remaining_urls = importer_handler.remaining_data
3333

changedetectionio/blueprint/price_data_follower/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ def accept(uuid):
2020
datastore.data['watching'][uuid]['processor'] = 'restock_diff'
2121
datastore.data['watching'][uuid].clear_watch()
2222
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid}))
23-
return redirect(url_for("index"))
23+
return redirect(url_for("watchlist.index"))
2424

2525
@login_required
2626
@price_data_follower_blueprint.route("/<string:uuid>/reject", methods=['GET'])
2727
def reject(uuid):
2828
datastore.data['watching'][uuid]['track_ldjson_price_data'] = PRICE_DATA_TRACK_REJECT
29-
return redirect(url_for("index"))
29+
return redirect(url_for("watchlist.index"))
3030

3131

3232
return price_data_follower_blueprint

changedetectionio/blueprint/rss/__init__.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ def construct_blueprint(datastore: ChangeDetectionStore):
1313

1414
# Import the login decorator if needed
1515
# from changedetectionio.auth_decorator import login_optionally_required
16-
17-
@rss_blueprint.route("/", methods=['GET'])
16+
@rss_blueprint.route("", methods=['GET'])
1817
def feed():
1918
now = time.time()
2019
# Always requires token set

changedetectionio/blueprint/settings/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
def construct_blueprint(datastore: ChangeDetectionStore):
1414
settings_blueprint = Blueprint('settings', __name__, template_folder="templates")
1515

16-
@settings_blueprint.route("/", methods=['GET', "POST"])
16+
@settings_blueprint.route("", methods=['GET', "POST"])
1717
@login_optionally_required
1818
def settings_page():
1919
from changedetectionio import forms
@@ -74,7 +74,7 @@ def settings_page():
7474
datastore.needs_write_urgent = True
7575
flash("Password protection enabled.", 'notice')
7676
flask_login.logout_user()
77-
return redirect(url_for('index'))
77+
return redirect(url_for('watchlist.index'))
7878

7979
datastore.needs_write_urgent = True
8080
flash("Settings updated.")

changedetectionio/blueprint/settings/templates/settings.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ <h4>Chrome Extension</h4>
299299
<div id="actions">
300300
<div class="pure-control-group">
301301
{{ render_button(form.save_button) }}
302-
<a href="{{url_for('index')}}" class="pure-button button-small button-cancel">Back</a>
302+
<a href="{{url_for('watchlist.index')}}" class="pure-button button-small button-cancel">Back</a>
303303
<a href="{{url_for('ui.clear_all_history')}}" class="pure-button button-small button-error">Clear Snapshot History</a>
304304
</div>
305305
</div>

changedetectionio/blueprint/tags/templates/groups-overview.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<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>
4848
</td>
4949
<td>{{ "{:,}".format(tag_count[uuid]) if uuid in tag_count else 0 }}</td>
50-
<td class="title-col inline"> <a href="{{url_for('index', tag=uuid) }}">{{ tag.title }}</a></td>
50+
<td class="title-col inline"> <a href="{{url_for('watchlist.index', tag=uuid) }}">{{ tag.title }}</a></td>
5151
<td>
5252
<a class="pure-button pure-button-primary" href="{{ url_for('tags.form_tag_edit', uuid=uuid) }}">Edit</a>&nbsp;
5353
<a class="pure-button pure-button-primary" href="{{ url_for('tags.delete', uuid=uuid) }}" title="Deletes and removes tag">Delete</a>

changedetectionio/blueprint/ui/__init__.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def clear_watch_history(uuid):
3636
else:
3737
flash("Cleared snapshot history for watch {}".format(uuid))
3838

39-
return redirect(url_for('index'))
39+
return redirect(url_for('watchlist.index'))
4040

4141
@ui_blueprint.route("/clear_history", methods=['GET', 'POST'])
4242
@login_optionally_required
@@ -52,7 +52,7 @@ def clear_all_history():
5252
else:
5353
flash('Incorrect confirmation text.', 'error')
5454

55-
return redirect(url_for('index'))
55+
return redirect(url_for('watchlist.index'))
5656

5757
output = render_template("clear_all_history.html")
5858
return output
@@ -68,7 +68,7 @@ def mark_all_viewed():
6868
continue
6969
datastore.set_last_viewed(watch_uuid, int(time.time()))
7070

71-
return redirect(url_for('index'))
71+
return redirect(url_for('watchlist.index'))
7272

7373
@ui_blueprint.route("/delete", methods=['GET'])
7474
@login_optionally_required
@@ -77,15 +77,15 @@ def form_delete():
7777

7878
if uuid != 'all' and not uuid in datastore.data['watching'].keys():
7979
flash('The watch by UUID {} does not exist.'.format(uuid), 'error')
80-
return redirect(url_for('index'))
80+
return redirect(url_for('watchlist.index'))
8181

8282
# More for testing, possible to return the first/only
8383
if uuid == 'first':
8484
uuid = list(datastore.data['watching'].keys()).pop()
8585
datastore.delete(uuid)
8686
flash('Deleted.')
8787

88-
return redirect(url_for('index'))
88+
return redirect(url_for('watchlist.index'))
8989

9090
@ui_blueprint.route("/clone", methods=['GET'])
9191
@login_optionally_required
@@ -101,7 +101,7 @@ def form_clone():
101101
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=5, item={'uuid': new_uuid}))
102102
flash('Cloned.')
103103

104-
return redirect(url_for('index'))
104+
return redirect(url_for('watchlist.index'))
105105

106106
@ui_blueprint.route("/checknow", methods=['GET'])
107107
@login_optionally_required
@@ -143,7 +143,7 @@ def form_watch_checknow():
143143
if i == 0:
144144
flash("No watches available to recheck.")
145145

146-
return redirect(url_for('index'))
146+
return redirect(url_for('watchlist.index'))
147147

148148
@ui_blueprint.route("/form/checkbox-operations", methods=['POST'])
149149
@login_optionally_required
@@ -244,7 +244,7 @@ def form_watch_list_checkbox_operations():
244244

245245
flash(f"{len(uuids)} watches were tagged")
246246

247-
return redirect(url_for('index'))
247+
return redirect(url_for('watchlist.index'))
248248

249249

250250
@ui_blueprint.route("/share-url/<string:uuid>", methods=['GET'])
@@ -296,6 +296,6 @@ def form_share_put_watch(uuid):
296296
logger.error(f"Error sharing -{str(e)}")
297297
flash(f"Could not share, something went wrong while communicating with the share server - {str(e)}", 'error')
298298

299-
return redirect(url_for('index'))
299+
return redirect(url_for('watchlist.index'))
300300

301301
return ui_blueprint

changedetectionio/blueprint/ui/edit.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ def edit_page(uuid):
3232
# More for testing, possible to return the first/only
3333
if not datastore.data['watching'].keys():
3434
flash("No watches to edit", "error")
35-
return redirect(url_for('index'))
35+
return redirect(url_for('watchlist.index'))
3636

3737
if uuid == 'first':
3838
uuid = list(datastore.data['watching'].keys()).pop()
3939

4040
if not uuid in datastore.data['watching']:
4141
flash("No watch with the UUID %s found." % (uuid), "error")
42-
return redirect(url_for('index'))
42+
return redirect(url_for('watchlist.index'))
4343

4444
switch_processor = request.args.get('switch_processor')
4545
if switch_processor:
@@ -66,7 +66,7 @@ def edit_page(uuid):
6666
processor_classes = next((tpl for tpl in processors.find_processors() if tpl[1] == processor_name), None)
6767
if not processor_classes:
6868
flash(f"Cannot load the edit form for processor/plugin '{processor_classes[1]}', plugin missing?", 'error')
69-
return redirect(url_for('index'))
69+
return redirect(url_for('watchlist.index'))
7070

7171
parent_module = processors.get_parent_module(processor_classes[0])
7272

@@ -207,7 +207,7 @@ def edit_page(uuid):
207207
if request.args.get("next") and request.args.get("next") == 'diff':
208208
return redirect(url_for('ui.ui_views.diff_history_page', uuid=uuid))
209209

210-
return redirect(url_for('index', tag=request.args.get("tag",'')))
210+
return redirect(url_for('watchlist.index', tag=request.args.get("tag",'')))
211211

212212
else:
213213
if request.method == 'POST' and not form.validate():

changedetectionio/blueprint/ui/templates/clear_all_history.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</div>
3838
<br />
3939
<div class="pure-control-group">
40-
<a href="{{url_for('index')}}" class="pure-button button-cancel"
40+
<a href="{{url_for('watchlist.index')}}" class="pure-button button-cancel"
4141
>Cancel</a
4242
>
4343
</div>

changedetectionio/blueprint/ui/views.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def preview_page(uuid):
2626
watch = datastore.data['watching'][uuid]
2727
except KeyError:
2828
flash("No history found for the specified link, bad link?", "error")
29-
return redirect(url_for('index'))
29+
return redirect(url_for('watchlist.index'))
3030

3131
system_uses_webdriver = datastore.data['settings']['application']['fetch_backend'] == 'html_webdriver'
3232
extra_stylesheets = [url_for('static_content', group='styles', filename='diff.css')]
@@ -91,7 +91,7 @@ def diff_history_page(uuid):
9191
watch = datastore.data['watching'][uuid]
9292
except KeyError:
9393
flash("No history found for the specified link, bad link?", "error")
94-
return redirect(url_for('index'))
94+
return redirect(url_for('watchlist.index'))
9595

9696
# For submission of requesting an extract
9797
extract_form = forms.extractDataForm(request.form)
@@ -119,7 +119,7 @@ def diff_history_page(uuid):
119119

120120
if len(dates) < 2:
121121
flash("Not enough saved change detection snapshots to produce a report.", "error")
122-
return redirect(url_for('index'))
122+
return redirect(url_for('watchlist.index'))
123123

124124
# Save the current newest history as the most recently viewed
125125
datastore.set_last_viewed(uuid, time.time())
@@ -196,7 +196,7 @@ def form_quick_watch_add():
196196
if not form.validate():
197197
for widget, l in form.errors.items():
198198
flash(','.join(l), 'error')
199-
return redirect(url_for('index'))
199+
return redirect(url_for('watchlist.index'))
200200

201201
url = request.form.get('url').strip()
202202
if datastore.url_exists(url):
@@ -215,6 +215,6 @@ def form_quick_watch_add():
215215
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': new_uuid}))
216216
flash("Watch added.")
217217

218-
return redirect(url_for('index', tag=request.args.get('tag','')))
218+
return redirect(url_for('watchlist.index', tag=request.args.get('tag','')))
219219

220220
return views_blueprint
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import flask_login
2+
import os
3+
import time
4+
import timeago
5+
6+
from flask import Blueprint, request, make_response, render_template, redirect, url_for, flash, session
7+
from flask_login import current_user
8+
from flask_paginate import Pagination, get_page_parameter
9+
10+
from changedetectionio import forms
11+
from changedetectionio.store import ChangeDetectionStore
12+
from changedetectionio.auth_decorator import login_optionally_required
13+
from changedetectionio.strtobool import strtobool
14+
15+
def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData):
16+
watchlist_blueprint = Blueprint('watchlist', __name__, template_folder="templates")
17+
18+
@watchlist_blueprint.route("/", methods=['GET'])
19+
@login_optionally_required
20+
def index():
21+
active_tag_req = request.args.get('tag', '').lower().strip()
22+
active_tag_uuid = active_tag = None
23+
24+
# Be sure limit_tag is a uuid
25+
if active_tag_req:
26+
for uuid, tag in datastore.data['settings']['application'].get('tags', {}).items():
27+
if active_tag_req == tag.get('title', '').lower().strip() or active_tag_req == uuid:
28+
active_tag = tag
29+
active_tag_uuid = uuid
30+
break
31+
32+
# Redirect for the old rss path which used the /?rss=true
33+
if request.args.get('rss'):
34+
return redirect(url_for('rss.feed', tag=active_tag_uuid))
35+
36+
op = request.args.get('op')
37+
if op:
38+
uuid = request.args.get('uuid')
39+
if op == 'pause':
40+
datastore.data['watching'][uuid].toggle_pause()
41+
elif op == 'mute':
42+
datastore.data['watching'][uuid].toggle_mute()
43+
44+
datastore.needs_write = True
45+
return redirect(url_for('watchlist.index', tag = active_tag_uuid))
46+
47+
# Sort by last_changed and add the uuid which is usually the key..
48+
sorted_watches = []
49+
with_errors = request.args.get('with_errors') == "1"
50+
errored_count = 0
51+
search_q = request.args.get('q').strip().lower() if request.args.get('q') else False
52+
for uuid, watch in datastore.data['watching'].items():
53+
if with_errors and not watch.get('last_error'):
54+
continue
55+
56+
if active_tag_uuid and not active_tag_uuid in watch['tags']:
57+
continue
58+
if watch.get('last_error'):
59+
errored_count += 1
60+
61+
if search_q:
62+
if (watch.get('title') and search_q in watch.get('title').lower()) or search_q in watch.get('url', '').lower():
63+
sorted_watches.append(watch)
64+
elif watch.get('last_error') and search_q in watch.get('last_error').lower():
65+
sorted_watches.append(watch)
66+
else:
67+
sorted_watches.append(watch)
68+
69+
form = forms.quickWatchForm(request.form)
70+
page = request.args.get(get_page_parameter(), type=int, default=1)
71+
total_count = len(sorted_watches)
72+
73+
pagination = Pagination(page=page,
74+
total=total_count,
75+
per_page=datastore.data['settings']['application'].get('pager_size', 50), css_framework="semantic")
76+
77+
sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title'])
78+
output = render_template(
79+
"watch-overview.html",
80+
# Don't link to hosting when we're on the hosting environment
81+
active_tag=active_tag,
82+
active_tag_uuid=active_tag_uuid,
83+
app_rss_token=datastore.data['settings']['application'].get('rss_access_token'),
84+
datastore=datastore,
85+
errored_count=errored_count,
86+
form=form,
87+
guid=datastore.data['app_guid'],
88+
has_proxies=datastore.proxy_list,
89+
has_unviewed=datastore.has_unviewed,
90+
hosted_sticky=os.getenv("SALTED_PASS", False) == False,
91+
pagination=pagination,
92+
queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
93+
search_q=request.args.get('q','').strip(),
94+
sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'),
95+
sort_order=request.args.get('order') if request.args.get('order') else request.cookies.get('order'),
96+
system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'),
97+
tags=sorted_tags,
98+
watches=sorted_watches
99+
)
100+
101+
if session.get('share-link'):
102+
del(session['share-link'])
103+
104+
resp = make_response(output)
105+
106+
# The template can run on cookie or url query info
107+
if request.args.get('sort'):
108+
resp.set_cookie('sort', request.args.get('sort'))
109+
if request.args.get('order'):
110+
resp.set_cookie('order', request.args.get('order'))
111+
112+
return resp
113+
114+
return watchlist_blueprint

0 commit comments

Comments
 (0)