diff --git a/Makefile b/Makefile index 53dca54..281989a 100644 --- a/Makefile +++ b/Makefile @@ -37,9 +37,11 @@ lint-fix: $(BLACK) $(FLASK_APP) serve: + echo 'Running on http://$(HOST):$(PORT)' $(FLASK) run --with-threads -h $(HOST) -p $(PORT) run: + echo 'Running on http://$(HOST):$(PORT)' FLASK_ENV=production && $(GUNICORN) -b 127.0.0.1:5000 "$(FLASK_APP):create_app()" --error-logfile $(GUNICORN_LOG) venv: diff --git a/docs/_sources/installation.rst.txt b/docs/_sources/installation.rst.txt index 4660ddb..f65b2dc 100644 --- a/docs/_sources/installation.rst.txt +++ b/docs/_sources/installation.rst.txt @@ -70,7 +70,7 @@ Installation -- The files location can be changed with the following environment variables: +- The files location and settings can be changed with the following environment variables: =========================== =============================================== =========================================================================================== variable description app default value @@ -91,35 +91,34 @@ Installation Usage ~~~~~ +.. versionchanged:: 0.7.0 + The following RSS feeds are available: - for Twitter search: - - http://localhost:8080/tweets/?token=XXX - - http://localhost:8080/?token=XXX (*will be deprecated in a next version*) + - http://localhost:8080/tweets?q=&token= - for Mastodon search: - - keyword as a hashtag: + - hashtag: - - http://localhost:8080/toots/?token=XXX (without the leading #) + - http://localhost:8080/toots/tags/?token= (without the leading #) - query: - - http://localhost:8080/toots/search/?token=XXX - - http://localhost:8080/toot_search/?token=XXX (*will be deprecated in a next version*) + - http://localhost:8080/toots/search?q=&token= -- for Mastodon connected user favorites: +- for Mastodon user favorites: - - http://localhost:8080/toots/favorites?token=XXX - - http://localhost:8080/toot_favorites?token=XXX (*will be deprecated in a next version*) + - http://localhost:8080/toots/favorites?token= -- for Mastodon connected user bookmarks: +- for Mastodon user bookmarks: - - http://localhost:8080/toots/bookmarks?token=XXX + - http://localhost:8080/toots/bookmarks?token= -- for Mastodon connected user home timeline: +- for Mastodon user home timeline: - - http://localhost:8080/toots/home_timeline?token=XXX + - http://localhost:8080/toots/home_timeline?token= -where XXX is the token set in configuration. \ No newline at end of file +where ```` is the token set in configuration. \ No newline at end of file diff --git a/docs/installation.html b/docs/installation.html index c828d13..34d1a36 100644 --- a/docs/installation.html +++ b/docs/installation.html @@ -143,7 +143,7 @@

Installation @@ -185,61 +185,61 @@

Installation

Usage

+
+

Changed in version 0.7.0.

+

The following RSS feeds are available:

-

where XXX is the token set in configuration.

+

where <token> is the token set in configuration.

diff --git a/docs/searchindex.js b/docs/searchindex.js index c6f2e17..1246c1d 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["changelog", "features", "how-to-developers", "index", "installation", "parameters"], "filenames": ["changelog.md", "features.rst", "how-to-developers.rst", "index.rst", "installation.rst", "parameters.rst"], "titles": ["Change log", "Features", "Quick start for developers", "Welcome to twootfeed\u2019s documentation!", "Installation and usage", "Application and feeds parameters"], "terms": {"updat": [0, 4], "depend": 0, "includ": [0, 4], "tweepi": [0, 2], "note": 0, "twootfe": [0, 1, 2, 4, 5], "still": 0, "us": [0, 1, 2, 4, 5], "twitter": [0, 1, 2, 3, 4], "api": [0, 1, 2, 4], "v1": 0, "issu": 0, "27": 0, "gener": [0, 1, 3, 4, 5], "document": 0, "sphinx": 0, "add": 0, "feed": [0, 1, 3, 4], "user": [0, 1, 4], "s": [0, 2, 4], "bookmark": [0, 1, 3, 4], "In": 0, "thi": [0, 2], "releas": 0, "were": 0, "close": 0, "toot": [0, 1, 4], "_": 0, "search": [0, 1, 3, 4, 5], "rout": 0, "return": 0, "404": 0, "error": 0, "wa": 0, "24": 0, "correct": 0, "http": [0, 2, 4, 5], "code": 0, "statu": 0, "when": 0, "kei": [0, 1, 2, 4, 5], "ar": [0, 1, 4, 5], "provid": 0, "22": 0, "The": [0, 1, 4], "number": [0, 1, 5], "worker": [0, 5], "server": [0, 2, 5], "can": [0, 4], "set": [0, 4], "21": 0, "pagin": 0, "get": [0, 2, 5], "19": 0, "environ": [0, 4], "variabl": [0, 4], "limit": 0, "item": [0, 1, 4, 5], "avoid": 0, "time": 0, "out": 0, "refer": 0, "charact": [0, 4], "titl": [0, 5], "now": [0, 4], "avail": [0, 4], "pypi": 0, "name": [0, 5], "url": [0, 1, 5], "displai": [0, 1, 4, 5], "usernam": [0, 1], "python": [0, 2, 4], "sinc": [0, 4], "refactor": 0, "continu": 0, "integr": 0, "test": 0, "coverag": 0, "perform": 0, "improv": 0, "gunicorn": [0, 2, 5], "product": 0, "16": 0, "long": 0, "tweet": [0, 1, 4], "truncat": 0, "imag": [0, 1], "longer": 0, "handl": 0, "tweeperror": 0, "rate": 0, "exceed": 0, "major": 0, "ad": 0, "makefil": 0, "eas": 0, "instal": [0, 3], "start": [0, 3, 4], "see": [0, 2, 4, 5], "readm": 0, "thank": 0, "georgedorn": 0, "pr": 0, "client": [0, 2, 4], "script": [0, 4, 5], "rss": [0, 1, 3, 4], "authent": [0, 5], "regist": [0, 4, 5], "app": [0, 4], "credenti": [0, 4, 5], "minor": 0, "flask": [0, 2], "instead": 0, "django": 0, "queri": [0, 4], "descript": [0, 4, 5], "extern": 0, "all": 0, "media": 0, "an": [1, 5], "from": [1, 3, 4, 5], "mastodon": [1, 2, 3, 4], "favorit": [1, 3, 4], "home": [1, 4], "timelin": [1, 4], "onli": [1, 2], "origin": 1, "retweet": 1, "link": [1, 5], "hashtag": [1, 4], "sourc": 1, "locat": [1, 4], "like": 1, "boost": 1, "favourit": 1, "develop": [1, 3, 5], "person": 1, "associ": 1, "mai": [1, 4], "contain": 1, "restrict": [1, 4], "visibl": [1, 4], "feedgener": 2, "standard": 2, "py": 2, "pytz": 2, "pyyaml": 2, "beautifulsoup": 2, "clone": 2, "repo": 2, "git": 2, "github": 2, "com": [2, 4, 5], "samr1": 2, "virtualenv": 2, "packag": 2, "cd": 2, "make": 2, "fill": [2, 4], "field": [2, 4], "you": [2, 4], "config": [2, 4, 5], "yml": [2, 4, 5], "next": [2, 4], "step": 2, "serv": 2, "pars": 3, "featur": 3, "usag": 3, "applic": [3, 4], "paramet": [3, 4], "quick": 3, "chang": [3, 4], "log": [3, 4], "3": 4, "7": 4, "pip": 4, "initi": 4, "configur": 4, "file": [4, 5], "twootfeed_init": 4, "copi": 4, "past": 4, "valu": 4, "consumerkei": [4, 5], "consumersecret": [4, 5], "wrapper": 4, "which": 4, "your": 4, "prompt": 4, "creat": [4, 5], "twootfeed_create_mastodon_cli": 4, "new": 4, "version": 4, "0": [4, 5], "connect": 4, "account": 4, "A": 4, "token": [4, 5], "mandatori": [4, 5], "access": [4, 5], "minimum": 4, "length": [4, 5], "25": 4, "some": 4, "exampl": 4, "10": 4, "5": 4, "main": 4, "jun": 4, "6": 4, "2022": 4, "18": 4, "49": 4, "26": 4, "gcc": 4, "12": 4, "1": 4, "linux": 4, "type": 4, "help": 4, "copyright": 4, "credit": 4, "licens": 4, "more": 4, "inform": 4, "import": 4, "secret": 4, "token_urlsaf": 4, "pgoes3qoslhxduzny_gmn6p5vwzqszqbgnb_vpupq7o": 4, "command": 4, "line": 4, "date": 4, "sha256sum": 4, "base64": 4, "head": 4, "c": 4, "echo": 4, "nwu2mze1zgm0mmvlzdg5ndnhn": 4, "follow": 4, "default": 4, "twootfeed_config_dir": 4, "directori": 4, "twootfeed_config_fil": 4, "full": 4, "path": 4, "dir": 4, "twootfeed_log": 4, "print": 4, "consol": 4, "twootfeed_set": 4, "productionconfig": 4, "localhost": [4, 5], "8080": [4, 5], "keyword": 4, "xxx": 4, "deprec": 4, "without": 4, "lead": 4, "toot_search": 4, "toot_favorit": 4, "home_timelin": 4, "where": 4, "store": 5, "q": 5, "result": 5, "social": 5, "client_id_fil": 5, "tootrss_clientcr": 5, "txt": 5, "access_token_fil": 5, "tootrss_usercr": 5, "app_nam": 5, "tootrss": 5, "identifi": 5, "languag": 5, "fr": 5, "author_nam": 5, "feed_url": 5, "5000": 5, "timezon": 5, "europ": 5, "pari": 5, "text_length_limit": 5, "100": 5, "max_item": 5, "20": 5, "host": 5, "port": 5, "nb_worker": 5, "4": 5, "defin": 5, "en": 5, "instanc": 5, "author": 5, "maximum": 5, "wsgi": 5}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"chang": 0, "log": 0, "version": 0, "0": 0, "6": 0, "8": 0, "2021": 0, "10": 0, "05": 0, "misc": 0, "7": 0, "2020": 0, "03": 0, "15": 0, "new": 0, "featur": [0, 1], "2019": 0, "20": 0, "5": 0, "09": 0, "23": 0, "bug": 0, "fix": 0, "4": 0, "08": 0, "31": 0, "3": 0, "2": 0, "01": 0, "26": 0, "1": 0, "25": 0, "2018": 0, "17": 0, "mastodon": [0, 5], "extend": 0, "support": 0, "14": 0, "make": 0, "04": 0, "favorit": 0, "2017": 0, "12": 0, "07": 0, "18": 0, "descript": 1, "quick": 2, "start": 2, "develop": 2, "depend": 2, "instal": [2, 4], "test": 2, "welcom": 3, "twootfe": 3, "s": 3, "document": 3, "content": 3, "usag": 4, "requir": 4, "applic": 5, "feed": 5, "paramet": 5, "twitter": 5, "app": 5}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) \ No newline at end of file +Search.setIndex({"docnames": ["changelog", "features", "how-to-developers", "index", "installation", "parameters"], "filenames": ["changelog.md", "features.rst", "how-to-developers.rst", "index.rst", "installation.rst", "parameters.rst"], "titles": ["Change log", "Features", "Quick start for developers", "Welcome to twootfeed\u2019s documentation!", "Installation and usage", "Application and feeds parameters"], "terms": {"updat": [0, 4], "depend": 0, "includ": [0, 4], "tweepi": [0, 2], "note": 0, "twootfe": [0, 1, 2, 4, 5], "still": 0, "us": [0, 1, 2, 4, 5], "twitter": [0, 1, 2, 3, 4], "api": [0, 1, 2, 4], "v1": 0, "issu": 0, "27": 0, "gener": [0, 1, 3, 4, 5], "document": 0, "sphinx": 0, "add": 0, "feed": [0, 1, 3, 4], "user": [0, 1, 4], "s": [0, 2, 4], "bookmark": [0, 1, 3, 4], "In": 0, "thi": [0, 2], "releas": 0, "were": 0, "close": 0, "toot": [0, 1, 4], "_": 0, "search": [0, 1, 3, 4, 5], "rout": 0, "return": 0, "404": 0, "error": 0, "wa": 0, "24": 0, "correct": 0, "http": [0, 2, 4, 5], "code": 0, "statu": 0, "when": 0, "kei": [0, 1, 2, 4, 5], "ar": [0, 1, 4, 5], "provid": 0, "22": 0, "The": [0, 1, 4], "number": [0, 1, 5], "worker": [0, 5], "server": [0, 2, 5], "can": [0, 4], "set": [0, 4], "21": 0, "pagin": 0, "get": [0, 2, 5], "19": 0, "environ": [0, 4], "variabl": [0, 4], "limit": 0, "item": [0, 1, 4, 5], "avoid": 0, "time": 0, "out": 0, "refer": 0, "charact": [0, 4], "titl": [0, 5], "now": [0, 4], "avail": [0, 4], "pypi": 0, "name": [0, 5], "url": [0, 1, 5], "displai": [0, 1, 4, 5], "usernam": [0, 1], "python": [0, 2, 4], "sinc": [0, 4], "refactor": 0, "continu": 0, "integr": 0, "test": 0, "coverag": 0, "perform": 0, "improv": 0, "gunicorn": [0, 2, 5], "product": 0, "16": 0, "long": 0, "tweet": [0, 1, 4], "truncat": 0, "imag": [0, 1], "longer": 0, "handl": 0, "tweeperror": 0, "rate": 0, "exceed": 0, "major": 0, "ad": 0, "makefil": 0, "eas": 0, "instal": [0, 3], "start": [0, 3, 4], "see": [0, 2, 4, 5], "readm": 0, "thank": 0, "georgedorn": 0, "pr": 0, "client": [0, 2, 4], "script": [0, 4, 5], "rss": [0, 1, 3, 4], "authent": [0, 5], "regist": [0, 4, 5], "app": [0, 4], "credenti": [0, 4, 5], "minor": 0, "flask": [0, 2], "instead": 0, "django": 0, "queri": [0, 4], "descript": [0, 4, 5], "extern": 0, "all": 0, "media": 0, "an": [1, 5], "from": [1, 3, 4, 5], "mastodon": [1, 2, 3, 4], "favorit": [1, 3, 4], "home": [1, 4], "timelin": [1, 4], "onli": [1, 2], "origin": 1, "retweet": 1, "link": [1, 5], "hashtag": [1, 4], "sourc": 1, "locat": [1, 4], "like": 1, "boost": 1, "favourit": 1, "develop": [1, 3, 5], "person": 1, "associ": 1, "mai": [1, 4], "contain": 1, "restrict": [1, 4], "visibl": [1, 4], "feedgener": 2, "standard": 2, "py": 2, "pytz": 2, "pyyaml": 2, "beautifulsoup": 2, "clone": 2, "repo": 2, "git": 2, "github": 2, "com": [2, 4, 5], "samr1": 2, "virtualenv": 2, "packag": 2, "cd": 2, "make": 2, "fill": [2, 4], "field": [2, 4], "you": [2, 4], "config": [2, 4, 5], "yml": [2, 4, 5], "next": 2, "step": 2, "serv": 2, "pars": 3, "featur": 3, "usag": 3, "applic": [3, 4], "paramet": [3, 4], "quick": 3, "chang": [3, 4], "log": [3, 4], "3": 4, "7": 4, "pip": 4, "initi": 4, "configur": 4, "file": [4, 5], "twootfeed_init": 4, "copi": 4, "past": 4, "valu": 4, "consumerkei": [4, 5], "consumersecret": [4, 5], "wrapper": 4, "which": 4, "your": 4, "prompt": 4, "creat": [4, 5], "twootfeed_create_mastodon_cli": 4, "new": 4, "version": 4, "0": [4, 5], "connect": 4, "account": 4, "A": 4, "token": [4, 5], "mandatori": [4, 5], "access": [4, 5], "minimum": 4, "length": [4, 5], "25": 4, "some": 4, "exampl": 4, "10": 4, "5": 4, "main": 4, "jun": 4, "6": 4, "2022": 4, "18": 4, "49": 4, "26": 4, "gcc": 4, "12": 4, "1": 4, "linux": 4, "type": 4, "help": 4, "copyright": 4, "credit": 4, "licens": 4, "more": 4, "inform": 4, "import": 4, "secret": 4, "token_urlsaf": 4, "pgoes3qoslhxduzny_gmn6p5vwzqszqbgnb_vpupq7o": 4, "command": 4, "line": 4, "date": 4, "sha256sum": 4, "base64": 4, "head": 4, "c": 4, "echo": 4, "nwu2mze1zgm0mmvlzdg5ndnhn": 4, "follow": 4, "default": 4, "twootfeed_config_dir": 4, "directori": 4, "twootfeed_config_fil": 4, "full": 4, "path": 4, "dir": 4, "twootfeed_log": 4, "print": 4, "consol": 4, "twootfeed_set": 4, "productionconfig": 4, "localhost": [4, 5], "8080": [4, 5], "q": [4, 5], "tag": 4, "without": 4, "lead": 4, "home_timelin": 4, "where": 4, "store": 5, "result": 5, "social": 5, "client_id_fil": 5, "tootrss_clientcr": 5, "txt": 5, "access_token_fil": 5, "tootrss_usercr": 5, "app_nam": 5, "tootrss": 5, "identifi": 5, "languag": 5, "fr": 5, "author_nam": 5, "feed_url": 5, "5000": 5, "timezon": 5, "europ": 5, "pari": 5, "text_length_limit": 5, "100": 5, "max_item": 5, "20": 5, "host": 5, "port": 5, "nb_worker": 5, "4": 5, "defin": 5, "en": 5, "instanc": 5, "author": 5, "maximum": 5, "wsgi": 5}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"chang": 0, "log": 0, "version": 0, "0": 0, "6": 0, "8": 0, "2021": 0, "10": 0, "05": 0, "misc": 0, "7": 0, "2020": 0, "03": 0, "15": 0, "new": 0, "featur": [0, 1], "2019": 0, "20": 0, "5": 0, "09": 0, "23": 0, "bug": 0, "fix": 0, "4": 0, "08": 0, "31": 0, "3": 0, "2": 0, "01": 0, "26": 0, "1": 0, "25": 0, "2018": 0, "17": 0, "mastodon": [0, 5], "extend": 0, "support": 0, "14": 0, "make": 0, "04": 0, "favorit": 0, "2017": 0, "12": 0, "07": 0, "18": 0, "descript": 1, "quick": 2, "start": 2, "develop": 2, "depend": 2, "instal": [2, 4], "test": 2, "welcom": 3, "twootfe": 3, "s": 3, "document": 3, "content": 3, "usag": 4, "requir": 4, "applic": 5, "feed": 5, "paramet": 5, "twitter": 5, "app": 5}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) \ No newline at end of file diff --git a/docsrc/source/installation.rst b/docsrc/source/installation.rst index 4660ddb..f65b2dc 100644 --- a/docsrc/source/installation.rst +++ b/docsrc/source/installation.rst @@ -70,7 +70,7 @@ Installation -- The files location can be changed with the following environment variables: +- The files location and settings can be changed with the following environment variables: =========================== =============================================== =========================================================================================== variable description app default value @@ -91,35 +91,34 @@ Installation Usage ~~~~~ +.. versionchanged:: 0.7.0 + The following RSS feeds are available: - for Twitter search: - - http://localhost:8080/tweets/?token=XXX - - http://localhost:8080/?token=XXX (*will be deprecated in a next version*) + - http://localhost:8080/tweets?q=&token= - for Mastodon search: - - keyword as a hashtag: + - hashtag: - - http://localhost:8080/toots/?token=XXX (without the leading #) + - http://localhost:8080/toots/tags/?token= (without the leading #) - query: - - http://localhost:8080/toots/search/?token=XXX - - http://localhost:8080/toot_search/?token=XXX (*will be deprecated in a next version*) + - http://localhost:8080/toots/search?q=&token= -- for Mastodon connected user favorites: +- for Mastodon user favorites: - - http://localhost:8080/toots/favorites?token=XXX - - http://localhost:8080/toot_favorites?token=XXX (*will be deprecated in a next version*) + - http://localhost:8080/toots/favorites?token= -- for Mastodon connected user bookmarks: +- for Mastodon user bookmarks: - - http://localhost:8080/toots/bookmarks?token=XXX + - http://localhost:8080/toots/bookmarks?token= -- for Mastodon connected user home timeline: +- for Mastodon user home timeline: - - http://localhost:8080/toots/home_timeline?token=XXX + - http://localhost:8080/toots/home_timeline?token= -where XXX is the token set in configuration. \ No newline at end of file +where ```` is the token set in configuration. \ No newline at end of file diff --git a/twootfeed/config.py b/twootfeed/config.py index 7f4201d..1801247 100644 --- a/twootfeed/config.py +++ b/twootfeed/config.py @@ -1,10 +1,10 @@ import os -import secrets from twootfeed import param +from twootfeed.tests.data import TEST_TOKEN if os.getenv('TWOOTFEED_SETTINGS') == 'TestingConfig': - param['feed']['token'] = secrets.token_urlsafe() + param['feed']['token'] = TEST_TOKEN class BaseConfig: diff --git a/twootfeed/mastodon/routes.py b/twootfeed/mastodon/routes.py index d220645..f0bf24f 100644 --- a/twootfeed/mastodon/routes.py +++ b/twootfeed/mastodon/routes.py @@ -1,6 +1,6 @@ from typing import Tuple -from flask import Blueprint +from flask import Blueprint, request from twootfeed import mastodon_api, param as mastodon_param from twootfeed.mastodon.generate_toots_feed import generate_xml from twootfeed.utils.decorator import require_token @@ -8,39 +8,39 @@ mastodon_bp = Blueprint('mastodon', __name__) -@mastodon_bp.route('/toots/', methods=['GET']) +@mastodon_bp.route('/toots/tags/', methods=['GET']) @require_token -def tootfeed_hashtag(hashtag: str) -> Tuple[str, int]: +def toots_feed_hashtag(tag: str) -> Tuple[str, int]: """generate a rss feed from parsed mastodon search""" - return generate_xml(mastodon_api, mastodon_param, {'hashtag': hashtag}) + return generate_xml(mastodon_api, mastodon_param, {'hashtag': tag}) -@mastodon_bp.route('/toots/search/', methods=['GET']) -@mastodon_bp.route('/toot_search/', methods=['GET']) +@mastodon_bp.route('/toots/search', methods=['GET']) @require_token -def tootfeed(query_feed: str) -> Tuple[str, int]: +def toots_feed_search() -> Tuple[str, int]: """generate a rss feed from parsed mastodon search""" - return generate_xml(mastodon_api, mastodon_param, {'query': query_feed}) + q = request.args.get('q') + if not q: + return 'missing query', 400 + return generate_xml(mastodon_api, mastodon_param, {'query': q}) @mastodon_bp.route('/toots/favorites', methods=['GET']) -@mastodon_bp.route('/toot_favorites', methods=['GET']) @require_token -def toot_favorites_feed() -> Tuple[str, int]: +def toots_favorites_feed() -> Tuple[str, int]: """generate a rss feed authenticated user's favorites""" return generate_xml(mastodon_api, mastodon_param, target='favorites') @mastodon_bp.route('/toots/bookmarks', methods=['GET']) -@mastodon_bp.route('/toot_bookmarks', methods=['GET']) @require_token -def toot_bookmarks_feed() -> Tuple[str, int]: +def toots_bookmarks_feed() -> Tuple[str, int]: """generate a rss feed authenticated user's bookmarks""" return generate_xml(mastodon_api, mastodon_param, target='bookmarks') -@mastodon_bp.route('/home_timeline', methods=['GET']) +@mastodon_bp.route('/toots/home_timeline', methods=['GET']) @require_token -def home_timeline() -> Tuple[str, int]: +def toots_home_timeline() -> Tuple[str, int]: """generate a rss feed authenticated user's bookmarks""" return generate_xml(mastodon_api, mastodon_param, target='home_timeline') diff --git a/twootfeed/tests/test_default_route.py b/twootfeed/tests/test_default_route.py index eb6eb1d..9dd7e43 100644 --- a/twootfeed/tests/test_default_route.py +++ b/twootfeed/tests/test_default_route.py @@ -1,6 +1,13 @@ +from unittest.mock import patch + from flask import Flask +from .utils import MastodonApi, Tweepy, TwitterApi + +@patch('twootfeed.twitter.generate_tweets_feed.tweepy', Tweepy([])) +@patch('twootfeed.twitter.routes.twitter_api', TwitterApi()) +@patch('twootfeed.mastodon.routes.mastodon_api', MastodonApi([])) def test_default_route(app: Flask) -> None: client = app.test_client() response = client.get('/') diff --git a/twootfeed/tests/test_routes.py b/twootfeed/tests/test_mastodon_routes.py similarity index 54% rename from twootfeed/tests/test_routes.py rename to twootfeed/tests/test_mastodon_routes.py index 7443314..1510264 100644 --- a/twootfeed/tests/test_routes.py +++ b/twootfeed/tests/test_mastodon_routes.py @@ -1,26 +1,29 @@ +from unittest.mock import patch from uuid import uuid4 import pytest from flask import Flask +from .data import TEST_TOKEN +from .utils import MastodonApi + MASTODON_ENDPOINTS = [ '/toots/favorites', - '/toot_favorites', '/toots/bookmarks', - '/toot_bookmarks', - '/home_timeline', + '/toots/home_timeline', ] -class TestTwitterRoutesToken: - endpoint = '/{keyword}' +@patch('twootfeed.mastodon.routes.mastodon_api', MastodonApi([])) +class TestMastodonTagsRoute: + endpoint = '/toots/tags/{tag}' def test_it_returns_401_when_token_is_missing( self, app_missing_token: Flask ) -> None: client = app_missing_token.test_client() - response = client.get(self.endpoint.format(keyword=uuid4().hex)) + response = client.get(self.endpoint.format(tag=uuid4().hex)) assert response.status_code == 401 data = response.data.decode() @@ -32,27 +35,35 @@ def test_it_returns_403_when_token_is_invalid( client = app_invalid_token.test_client() response = client.get( - f'{self.endpoint.format(keyword=uuid4().hex)}?token=invalid' + f'{self.endpoint.format(tag=uuid4().hex)}?token=invalid' ) assert response.status_code == 403 data = response.data.decode() assert data == 'invalid token' + def test_it_returns_200_when_tag_is_provided(self, app: Flask) -> None: + client = app.test_client() -class TestTwitterTweetsRouteToken(TestTwitterRoutesToken): - endpoint = '/tweets/{keyword}' + response = client.get( + f'{self.endpoint.format(tag=uuid4().hex)}?&token={TEST_TOKEN}' + ) + assert response.status_code == 200 + data = response.data.decode() + assert '' in data -class TestMastodonHashtagRouteToken: - endpoint = '/toots/{hashtag}' + +@patch('twootfeed.mastodon.routes.mastodon_api', MastodonApi([])) +class TestMastodonSearchRoute: + endpoint = '/toots/search' def test_it_returns_401_when_token_is_missing( self, app_missing_token: Flask ) -> None: client = app_missing_token.test_client() - response = client.get(self.endpoint.format(hashtag=uuid4().hex)) + response = client.get(self.endpoint) assert response.status_code == 401 data = response.data.decode() @@ -63,48 +74,35 @@ def test_it_returns_403_when_token_is_invalid( ) -> None: client = app_invalid_token.test_client() - response = client.get( - f'{self.endpoint.format(hashtag=uuid4().hex)}?token=invalid' - ) + response = client.get(f'{self.endpoint}?token=invalid') assert response.status_code == 403 data = response.data.decode() assert data == 'invalid token' + def test_it_returns_400_when_query_is_missing(self, app: Flask) -> None: + client = app.test_client() -class TestMastodonSearchRouteToken: - endpoint = '/toots/search/{query_feed}' + response = client.get(f'{self.endpoint}?token={TEST_TOKEN}') - def test_it_returns_401_when_token_is_missing( - self, app_missing_token: Flask - ) -> None: - client = app_missing_token.test_client() - - response = client.get(self.endpoint.format(query_feed=uuid4().hex)) - - assert response.status_code == 401 + assert response.status_code == 400 data = response.data.decode() - assert data == 'missing token' + assert data == 'missing query' - def test_it_returns_403_when_token_is_invalid( - self, app_invalid_token: Flask - ) -> None: - client = app_invalid_token.test_client() + def test_it_returns_200_when_query_is_provided(self, app: Flask) -> None: + client = app.test_client() response = client.get( - f'{self.endpoint.format(query_feed=uuid4().hex)}?token=invalid' + f'{self.endpoint}?q={uuid4().hex}&token={TEST_TOKEN}' ) - assert response.status_code == 403 + assert response.status_code == 200 data = response.data.decode() - assert data == 'invalid token' + assert '' in data -class TestMastodonSearchAlternativeRouteToken(TestMastodonSearchRouteToken): - endpoint = '/toot_search/{query_feed}' - - -class TestMastodonRoutesToken: +@patch('twootfeed.mastodon.routes.mastodon_api', MastodonApi([])) +class TestMastodonRoutes: @pytest.mark.parametrize('input_endpoint', MASTODON_ENDPOINTS) def test_it_returns_401_when_token_is_missing( self, app_missing_token: Flask, input_endpoint: str @@ -128,3 +126,13 @@ def test_it_returns_403_when_token_is_invalid( assert response.status_code == 403 data = response.data.decode() assert data == 'invalid token' + + @pytest.mark.parametrize('input_endpoint', MASTODON_ENDPOINTS) + def test_it_returns_200(self, app: Flask, input_endpoint: str) -> None: + client = app.test_client() + + response = client.get(f'{input_endpoint}?token={TEST_TOKEN}') + + assert response.status_code == 200 + data = response.data.decode() + assert '' in data diff --git a/twootfeed/tests/test_twitter_routes.py b/twootfeed/tests/test_twitter_routes.py new file mode 100644 index 0000000..0066efa --- /dev/null +++ b/twootfeed/tests/test_twitter_routes.py @@ -0,0 +1,55 @@ +from unittest.mock import patch +from uuid import uuid4 + +from flask import Flask + +from .data import TEST_TOKEN +from .utils import Tweepy, TwitterApi + + +@patch('twootfeed.twitter.generate_tweets_feed.tweepy', Tweepy([])) +@patch('twootfeed.twitter.routes.twitter_api', TwitterApi()) +class TestTwitterRoutes: + endpoint = '/tweets' + + def test_it_returns_401_when_token_is_missing( + self, app_missing_token: Flask + ) -> None: + client = app_missing_token.test_client() + + response = client.get(self.endpoint) + + assert response.status_code == 401 + data = response.data.decode() + assert data == 'missing token' + + def test_it_returns_403_when_token_is_invalid( + self, app_invalid_token: Flask + ) -> None: + client = app_invalid_token.test_client() + + response = client.get(f'{self.endpoint}?token=invalid') + + assert response.status_code == 403 + data = response.data.decode() + assert data == 'invalid token' + + def test_it_returns_400_when_query_is_missing(self, app: Flask) -> None: + client = app.test_client() + + response = client.get(f'{self.endpoint}?token={TEST_TOKEN}') + + assert response.status_code == 400 + data = response.data.decode() + assert data == 'missing query' + + def test_it_returns_200_when_query_is_provided(self, app: Flask) -> None: + client = app.test_client() + + response = client.get( + f'{self.endpoint}?q={uuid4().hex}&token={TEST_TOKEN}' + ) + + assert response.status_code == 200 + data = response.data.decode() + assert '' in data diff --git a/twootfeed/tests/utils.py b/twootfeed/tests/utils.py index 5dd1b62..13542ee 100644 --- a/twootfeed/tests/utils.py +++ b/twootfeed/tests/utils.py @@ -50,6 +50,9 @@ def __init__(self, tweets: List): self.tweet_pages = self.items_in_pages(tweets) self.tweets = [ToDotNotationTweepy(tweet) for tweet in tweets] + def Cursor(self, *args: Any, **kwargs: Any) -> 'Tweepy': + return self + def pages(self) -> List[List[ToDotNotationTweepy]]: return self.tweet_pages diff --git a/twootfeed/twitter/routes.py b/twootfeed/twitter/routes.py index 3e293b7..2726b0e 100644 --- a/twootfeed/twitter/routes.py +++ b/twootfeed/twitter/routes.py @@ -1,6 +1,6 @@ from typing import Tuple -from flask import Blueprint +from flask import Blueprint, request from twootfeed import param, twitter_api from twootfeed.twitter.generate_tweets_feed import generate_xml from twootfeed.utils.decorator import require_token @@ -8,9 +8,11 @@ twitter_bp = Blueprint('twitter', __name__) -@twitter_bp.route('/', methods=['GET']) -@twitter_bp.route('/tweets/', methods=['GET']) +@twitter_bp.route('/tweets', methods=['GET']) @require_token -def tweetfeed(query_feed: str) -> Tuple[str, int]: +def tweetfeed() -> Tuple[str, int]: """generate a rss feed from parsed twitter search""" - return generate_xml(twitter_api, query_feed, param) + q = request.args.get('q') + if not q: + return 'missing query', 400 + return generate_xml(twitter_api, q, param) diff --git a/twootfeed/utils/decorator.py b/twootfeed/utils/decorator.py index 6a4a133..715cbd6 100644 --- a/twootfeed/utils/decorator.py +++ b/twootfeed/utils/decorator.py @@ -1,8 +1,7 @@ from functools import wraps from typing import Any, Callable, Tuple, Union -from flask import request -from twootfeed import param +from flask import current_app, request def require_token(f: Callable) -> Callable: @@ -13,7 +12,7 @@ def decorated_function( token = request.args.get('token') if not token: return 'missing token', 401 - if token != param['feed']['token']: + if token != current_app.config['FEED_CONFIG']['token']: return 'invalid token', 403 return f(*args, **kwargs)