Skip to content

Commit 8cd2645

Browse files
committed
feat: Save feed URL on redirect
Also adds test for saving feed URL on redirect.
1 parent 63d657c commit 8cd2645

File tree

4 files changed

+48
-10
lines changed

4 files changed

+48
-10
lines changed

rss2email/command.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def run(feeds, args):
9494
interval = interval
9595
))
9696
_time.sleep(interval)
97-
feed.run(send=args.send, clean=args.clean)
97+
feed.run(send=args.send, clean=args.clean, save_config=args.save_config)
9898
except _error.RSS2EmailError as e:
9999
e.log()
100100
last_server = current_server

rss2email/feed.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,9 @@ def _fetch(self):
386386
f = _util.TimeLimitedFunction('feed {}'.format(self.name), timeout, _feedparser.parse)
387387
return f(self.url, self.etag, modified=self.modified, agent=self.user_agent, **kwargs)
388388

389-
def _process(self, parsed):
389+
def _process(self, parsed, save_config=False):
390390
_LOG.info('process {}'.format(self))
391-
self._check_for_errors(parsed)
391+
self._check_for_errors(parsed, save_config=save_config)
392392
for entry in reversed(parsed.entries):
393393
_LOG.debug('processing {}'.format(entry.get('id', 'no-id')))
394394
processed = self._process_entry(parsed=parsed, entry=entry)
@@ -402,15 +402,16 @@ def _process(self, parsed):
402402
continue
403403
yield processed
404404

405-
def _check_for_errors(self, parsed):
405+
def _check_for_errors(self, parsed, save_config=False):
406406
warned = False
407407
status = getattr(parsed, 'status', 200)
408408
_LOG.debug('HTTP status {}'.format(status))
409409
if status in [301, 308]:
410410
_LOG.info('redirect {} from {} to {}'.format(
411411
self.name, self.url, parsed['url']))
412412
self.url = parsed['url']
413-
# TODO: `url` is not saved -- add config option to call feeds.save_config() in run command
413+
if save_config:
414+
self.save_to_config()
414415
elif status == 304:
415416
_LOG.info('skipping {}: feed was not modified since last update'.format(
416417
self.name, self.url))
@@ -917,7 +918,7 @@ def _send(self, sender, message):
917918
_email.send(recipient=self.to, message=message,
918919
config=self.config, section=section)
919920

920-
def run(self, send=True, clean=False):
921+
def run(self, send=True, clean=False, save_config=False):
921922
"""Fetch and process the feed, mailing entry emails.
922923
923924
>>> feed = Feed(
@@ -947,7 +948,7 @@ def run(self, send=True, clean=False):
947948
raise _error.InvalidDigestType(type)
948949
digest = self._new_digest()
949950
seen = []
950-
for (guid, state, sender, message) in self._process(parsed):
951+
for (guid, state, sender, message) in self._process(parsed, save_config=save_config):
951952
_LOG.debug('new message: {}'.format(message['Subject']))
952953
seen.append((guid, state))
953954
self._append_to_digest(digest=digest, message=message)
@@ -962,7 +963,7 @@ def run(self, send=True, clean=False):
962963
for (guid, state) in seen:
963964
self.seen[guid] = state
964965
else:
965-
for (guid, state, sender, message) in self._process(parsed):
966+
for (guid, state, sender, message) in self._process(parsed, save_config=save_config):
966967
_LOG.debug('new message: {}'.format(message['Subject']))
967968
if send:
968969
self._send(sender=sender, message=message)

rss2email/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ def run(*args, **kwargs):
112112
default=True, action='store_const', const=False,
113113
help="fetch feeds, but don't send email")
114114
run_parser.add_argument(
115-
'--clean', action='store_true',
116-
help='clean old feed entries')
115+
'--save-config', action='store_true',
116+
help='save feed configuration changes (e.g. new URL after a redirect)')
117117
run_parser.add_argument(
118118
'index', nargs='*',
119119
help='feeds to fetch (defaults to fetching all feeds)')

test/test_main.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,22 @@ def webserver_for_test_if_fetch(queue, timeout):
249249
finally:
250250
httpd.server_close()
251251

252+
def webserver_for_test_redirect(queue, status_code):
253+
class RedirectHandler(NoLogHandler):
254+
def do_GET(self):
255+
self.send_response(status_code)
256+
self.send_header('Location', '/disqus/feed.rss')
257+
self.end_headers()
258+
259+
httpd = http.server.HTTPServer(('', 0), RedirectHandler)
260+
try:
261+
port = httpd.server_address[1]
262+
queue.put(port)
263+
while queue.get() != "stop":
264+
httpd.handle_request()
265+
finally:
266+
httpd.server_close()
267+
252268
class TestFetch(unittest.TestCase):
253269
"Retrieving feeds from servers"
254270
def test_delay(self):
@@ -379,6 +395,27 @@ def test_only_new(self):
379395
self.assertIn("seen", content["feeds"][0])
380396
self.assertEqual(queue.get(), "done")
381397

398+
def test_redirect(self):
399+
"Saves feed URL on redirect"
400+
cfg = """[DEFAULT]
401+
402+
403+
queue = multiprocessing.Queue()
404+
webserver_proc = multiprocessing.Process(target=webserver_for_test_redirect, args=(queue, 301))
405+
webserver_proc.start()
406+
port = queue.get()
407+
408+
with ExecContext(cfg) as ctx:
409+
ctx.call("add", 'test', 'http://127.0.0.1:{port}/redirect'.format(port = port))
410+
411+
queue.put("next")
412+
ctx.call("run", "--no-send", "--save-config")
413+
414+
with open(ctx.cfg_path, 'r') as f:
415+
config = f.read()
416+
self.assertIn("url = http://127.0.0.1:{port}/disqus/feed.rss".format(port=port), config)
417+
418+
queue.put("stop")
382419

383420
def webserver_for_test_send(queue):
384421
httpd = http.server.HTTPServer(('', 0), NoLogHandler)

0 commit comments

Comments
 (0)