250 lines
10 KiB
Python
250 lines
10 KiB
Python
import base64
|
|
import flask; from flask import request
|
|
import traceback
|
|
|
|
from voussoirkit import stringtools
|
|
from voussoirkit import flasktools
|
|
from voussoirkit import vlogging
|
|
|
|
log = vlogging.get_logger(__name__)
|
|
|
|
from .. import common
|
|
|
|
import bringrss
|
|
|
|
site = common.site
|
|
|
|
# Feed listings ####################################################################################
|
|
|
|
@site.route('/feeds.json')
|
|
@flasktools.cached_endpoint(max_age=0, etag_function=lambda: common.bringdb.last_commit_id)
|
|
def get_feeds_json():
|
|
feeds = common.bringdb.get_feeds()
|
|
response = []
|
|
unread_counts = common.bringdb.get_bulk_unread_counts()
|
|
for feed in feeds:
|
|
j = feed.jsonify()
|
|
j['unread_count'] = unread_counts.get(feed, 0)
|
|
response.append(j)
|
|
return flasktools.json_response(response)
|
|
|
|
@site.route('/feeds/add', methods=['POST'])
|
|
def post_feeds_add():
|
|
rss_url = request.form.get('rss_url')
|
|
title = request.form.get('title')
|
|
isolate_guids = request.form.get('isolate_guids', False)
|
|
isolate_guids = stringtools.truthystring(isolate_guids)
|
|
with common.bringdb.transaction:
|
|
feed = common.bringdb.add_feed(rss_url=rss_url, title=title, isolate_guids=isolate_guids)
|
|
|
|
# We want to refresh the feed now and not just put it on the refresh queue,
|
|
# because when the user gets the response to this endpoint they will
|
|
# navigate to the /settings, and we want to have that page pre-populated
|
|
# with the title and icon. If the feed goes to the refresh queue, the page
|
|
# will come up blank, then get populated in the background, which is bad
|
|
# ux. However, we need to commit first, because if the refresh fails we want
|
|
# the user to be able to see the Feed in the ui and read its
|
|
# last_refresh_error message.
|
|
with common.bringdb.transaction:
|
|
try:
|
|
feed.refresh()
|
|
except Exception:
|
|
log.warning('Refreshing %s raised:\n%s', feed, traceback.format_exc())
|
|
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feeds/refresh_all', methods=['POST'])
|
|
def post_feeds_refresh_all():
|
|
predicate = lambda feed: feed.refresh_with_others
|
|
# The root feeds are not exempt from the predicate because the user clicked
|
|
# the refresh all button, not the root feed specifically.
|
|
root_feeds = [root for root in common.bringdb.get_root_feeds() if predicate(root)]
|
|
for root_feed in root_feeds:
|
|
for feed in root_feed.walk_children(predicate=predicate, yield_self=True):
|
|
common.add_feed_to_refresh_queue(feed)
|
|
return flasktools.json_response({})
|
|
|
|
# Individual feeds #################################################################################
|
|
|
|
@site.route('/feed/<feed_id>.json')
|
|
def get_feed_json(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/delete', methods=['POST'])
|
|
def post_feed_delete(feed_id):
|
|
with common.bringdb.transaction:
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
feed.delete()
|
|
return flasktools.json_response({})
|
|
|
|
@site.route('/feed/<feed_id>/icon.png')
|
|
def get_feed_icon(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='html')
|
|
|
|
if feed.icon:
|
|
headers = {'Cache-Control': f'max-age={common.BROWSER_CACHE_DURATION}'}
|
|
return flask.Response(feed.icon, mimetype='image/png', headers=headers)
|
|
elif feed.rss_url:
|
|
basic = common.STATIC_DIR.with_child('basic_icons').with_child('rss.png')
|
|
return flask.send_file(basic.absolute_path)
|
|
else:
|
|
basic = common.STATIC_DIR.with_child('basic_icons').with_child('folder.png')
|
|
return flask.send_file(basic.absolute_path)
|
|
|
|
@site.route('/feed/<feed_id>/refresh', methods=['POST'])
|
|
def post_feed_refresh(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
|
|
predicate = lambda child: child.refresh_with_others
|
|
# We definitely want to refresh this feed regardless of the predicate,
|
|
# because that's what was requested.
|
|
feeds = list(feed.walk_children(predicate=predicate, yield_self=True))
|
|
for feed in feeds:
|
|
common.add_feed_to_refresh_queue(feed)
|
|
|
|
return flasktools.json_response({})
|
|
|
|
@site.route('/feed/<feed_id>/settings')
|
|
def get_feed_settings(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='html')
|
|
feed_filters = list(feed.get_filters())
|
|
available_filters = set(common.bringdb.get_filters())
|
|
available_filters.difference_update(feed_filters)
|
|
return common.render_template(
|
|
request,
|
|
'feed_settings.html',
|
|
feed=feed,
|
|
feed_filters=feed_filters,
|
|
available_filters=available_filters,
|
|
)
|
|
|
|
@site.route('/feed/<feed_id>/set_autorefresh_interval', methods=['POST'])
|
|
@flasktools.required_fields(['autorefresh_interval'])
|
|
def post_feed_set_autorefresh_interval(feed_id):
|
|
autorefresh_interval = request.form['autorefresh_interval']
|
|
try:
|
|
autorefresh_interval = int(autorefresh_interval)
|
|
except ValueError:
|
|
return flasktools.json_response({}, status=400)
|
|
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
if autorefresh_interval != feed.autorefresh_interval:
|
|
with common.bringdb.transaction:
|
|
feed.set_autorefresh_interval(autorefresh_interval)
|
|
# Wake up the autorefresh thread so it can recalculate its schedule.
|
|
common.AUTOREFRESH_THREAD_EVENTS.put("wake up!")
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_filters', methods=['POST'])
|
|
@flasktools.required_fields(['filter_ids'])
|
|
def post_feed_set_filters(feed_id):
|
|
filter_ids = stringtools.comma_space_split(request.form['filter_ids'])
|
|
with common.bringdb.transaction:
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
filters = [common.get_filter(id, response_type='json') for id in filter_ids]
|
|
feed.set_filters(filters)
|
|
return flasktools.json_response(feed.jsonify(filters=True))
|
|
|
|
@site.route('/feed/<feed_id>/set_http_headers', methods=['POST'])
|
|
@flasktools.required_fields(['http_headers'])
|
|
def post_feed_set_http_headers(feed_id):
|
|
with common.bringdb.transaction:
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
feed.set_http_headers(request.form['http_headers'])
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_icon', methods=['POST'])
|
|
@flasktools.required_fields(['image_base64'])
|
|
def post_feed_set_icon(feed_id):
|
|
image_base64 = request.form['image_base64']
|
|
image_base64 = image_base64.split(';base64,')[-1]
|
|
image_binary = base64.b64decode(image_base64)
|
|
with common.bringdb.transaction:
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
feed.set_icon(image_binary)
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_isolate_guids', methods=['POST'])
|
|
@flasktools.required_fields(['isolate_guids'])
|
|
def post_feed_set_isolate_guids(feed_id):
|
|
try:
|
|
isolate_guids = stringtools.truthystring(request.form['isolate_guids'])
|
|
except ValueError:
|
|
return flasktools.json_response({}, status=400)
|
|
with common.bringdb.transaction:
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
feed.set_isolate_guids(isolate_guids)
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_parent', methods=['POST'])
|
|
@flasktools.required_fields(['parent_id'])
|
|
def post_feed_set_parent(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
|
|
parent_id = request.form['parent_id']
|
|
if parent_id == '':
|
|
parent = None
|
|
else:
|
|
parent = common.get_feed(parent_id, response_type='json')
|
|
|
|
ui_order_rank = request.form.get('ui_order_rank', None)
|
|
if ui_order_rank is not None:
|
|
ui_order_rank = float(ui_order_rank)
|
|
|
|
if parent != feed.parent or ui_order_rank != feed.ui_order_rank:
|
|
with common.bringdb.transaction:
|
|
feed.set_parent(parent, ui_order_rank=ui_order_rank)
|
|
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_refresh_with_others', methods=['POST'])
|
|
@flasktools.required_fields(['refresh_with_others'])
|
|
def post_feed_set_refresh_with_others(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
refresh_with_others = stringtools.truthystring(request.form['refresh_with_others'])
|
|
if refresh_with_others != feed.refresh_with_others:
|
|
with common.bringdb.transaction:
|
|
feed.set_refresh_with_others(refresh_with_others)
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_rss_url', methods=['POST'])
|
|
@flasktools.required_fields(['rss_url'])
|
|
def post_feed_set_rss_url(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
rss_url = request.form['rss_url']
|
|
if rss_url != feed.rss_url:
|
|
with common.bringdb.transaction:
|
|
feed.set_rss_url(rss_url)
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_web_url', methods=['POST'])
|
|
@flasktools.required_fields(['web_url'])
|
|
def post_feed_set_web_url(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
web_url = request.form['web_url']
|
|
if web_url != feed.web_url:
|
|
with common.bringdb.transaction:
|
|
feed.set_web_url(web_url)
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_title', methods=['POST'])
|
|
@flasktools.required_fields(['title'])
|
|
def post_feed_set_title(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
title = request.form['title']
|
|
if title != feed.title:
|
|
with common.bringdb.transaction:
|
|
feed.set_title(title)
|
|
return flasktools.json_response(feed.jsonify())
|
|
|
|
@site.route('/feed/<feed_id>/set_ui_order_rank', methods=['POST'])
|
|
@flasktools.required_fields(['ui_order_rank'], forbid_whitespace=True)
|
|
def post_feed_set_ui_order_rank(feed_id):
|
|
feed = common.get_feed(feed_id, response_type='json')
|
|
ui_order_rank = float(request.form['ui_order_rank'])
|
|
if ui_order_rank != feed.ui_order_rank:
|
|
with common.bringdb.transaction:
|
|
feed.set_ui_order_rank(ui_order_rank)
|
|
common.bringdb.reassign_ui_order_rank()
|
|
return flasktools.json_response(feed.jsonify())
|