0.3.9
This commit is contained in:
parent
00164bd3b5
commit
c61ce0bcb7
17 changed files with 238 additions and 673 deletions
|
|
@ -1,5 +1,10 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.3.9
|
||||||
|
|
||||||
|
- Cursor based pagination
|
||||||
|
- Updated django version
|
||||||
|
|
||||||
## 0.3.8
|
## 0.3.8
|
||||||
|
|
||||||
- Update light / dark theme
|
- Update light / dark theme
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "newsreader",
|
"name": "newsreader",
|
||||||
"version": "0.1.0",
|
"version": "0.3.9",
|
||||||
"description": "Application for viewing RSS feeds",
|
"description": "Application for viewing RSS feeds",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
148
poetry.lock
generated
148
poetry.lock
generated
|
|
@ -37,10 +37,10 @@ optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"]
|
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"]
|
||||||
docs = ["furo", "sphinx", "zope.interface"]
|
docs = ["furo", "sphinx", "zope.interface"]
|
||||||
tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
||||||
tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
|
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autoflake"
|
name = "autoflake"
|
||||||
|
|
@ -61,15 +61,13 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
soupsieve = {version = ">1.2", markers = "python_version >= \"3.0\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
html5lib = ["html5lib"]
|
html5lib = ["html5lib"]
|
||||||
lxml = ["lxml"]
|
lxml = ["lxml"]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
[package.dependencies.soupsieve]
|
|
||||||
version = ">1.2"
|
|
||||||
python = ">=3.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "billiard"
|
name = "billiard"
|
||||||
version = "3.6.3.0"
|
version = "3.6.3.0"
|
||||||
|
|
@ -86,15 +84,15 @@ category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
appdirs = "*"
|
appdirs = "*"
|
||||||
attrs = ">=18.1.0"
|
attrs = ">=18.1.0"
|
||||||
click = ">=6.5"
|
click = ">=6.5"
|
||||||
toml = ">=0.9.4"
|
toml = ">=0.9.4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bleach"
|
name = "bleach"
|
||||||
version = "3.2.1"
|
version = "3.2.1"
|
||||||
|
|
@ -116,14 +114,20 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
billiard = ">=3.6.3.0,<4.0"
|
||||||
|
kombu = ">=4.6.10,<4.7"
|
||||||
|
pytz = ">0.0-dev"
|
||||||
|
vine = "1.3.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
arangodb = ["pyArango (>=1.3.2)"]
|
arangodb = ["pyArango (>=1.3.2)"]
|
||||||
auth = ["cryptography"]
|
auth = ["cryptography"]
|
||||||
azureblockblob = ["azure-storage (0.36.0)", "azure-common (1.1.5)", "azure-storage-common (1.1.0)"]
|
azureblockblob = ["azure-storage (==0.36.0)", "azure-common (==1.1.5)", "azure-storage-common (==1.1.0)"]
|
||||||
brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"]
|
brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"]
|
||||||
cassandra = ["cassandra-driver (<3.21.0)"]
|
cassandra = ["cassandra-driver (<3.21.0)"]
|
||||||
consul = ["python-consul"]
|
consul = ["python-consul"]
|
||||||
cosmosdbsql = ["pydocumentdb (2.3.2)"]
|
cosmosdbsql = ["pydocumentdb (==2.3.2)"]
|
||||||
couchbase = ["couchbase-cffi (<3.0.0)", "couchbase (<3.0.0)"]
|
couchbase = ["couchbase-cffi (<3.0.0)", "couchbase (<3.0.0)"]
|
||||||
couchdb = ["pycouchdb"]
|
couchdb = ["pycouchdb"]
|
||||||
django = ["Django (>=1.11)"]
|
django = ["Django (>=1.11)"]
|
||||||
|
|
@ -134,7 +138,7 @@ gevent = ["gevent"]
|
||||||
librabbitmq = ["librabbitmq (>=1.5.0)"]
|
librabbitmq = ["librabbitmq (>=1.5.0)"]
|
||||||
lzma = ["backports.lzma"]
|
lzma = ["backports.lzma"]
|
||||||
memcache = ["pylibmc"]
|
memcache = ["pylibmc"]
|
||||||
mongodb = ["pymongo (>=3.3.0)"]
|
mongodb = ["pymongo[srv] (>=3.3.0)"]
|
||||||
msgpack = ["msgpack"]
|
msgpack = ["msgpack"]
|
||||||
pymemcache = ["python-memcached"]
|
pymemcache = ["python-memcached"]
|
||||||
pyro = ["pyro4"]
|
pyro = ["pyro4"]
|
||||||
|
|
@ -144,18 +148,12 @@ s3 = ["boto3 (>=1.9.125)"]
|
||||||
slmq = ["softlayer-messaging (>=1.0.3)"]
|
slmq = ["softlayer-messaging (>=1.0.3)"]
|
||||||
solar = ["ephem"]
|
solar = ["ephem"]
|
||||||
sqlalchemy = ["sqlalchemy"]
|
sqlalchemy = ["sqlalchemy"]
|
||||||
sqs = ["boto3 (>=1.9.125)", "pycurl (7.43.0.5)"]
|
sqs = ["boto3 (>=1.9.125)", "pycurl (==7.43.0.5)"]
|
||||||
tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"]
|
tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"]
|
||||||
yaml = ["PyYAML (>=3.10)"]
|
yaml = ["PyYAML (>=3.10)"]
|
||||||
zookeeper = ["kazoo (>=1.3.1)"]
|
zookeeper = ["kazoo (>=1.3.1)"]
|
||||||
zstd = ["zstandard"]
|
zstd = ["zstandard"]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
billiard = ">=3.6.3.0,<4.0"
|
|
||||||
kombu = ">=4.6.10,<4.7"
|
|
||||||
pytz = ">0.0-dev"
|
|
||||||
vine = "1.3.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2020.12.5"
|
version = "2020.12.5"
|
||||||
|
|
@ -218,21 +216,21 @@ toml = ["toml"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django"
|
name = "django"
|
||||||
version = "3.1.5"
|
version = "3.1.6"
|
||||||
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
|
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
argon2 = ["argon2-cffi (>=16.1.0)"]
|
|
||||||
bcrypt = ["bcrypt"]
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
asgiref = ">=3.2.10,<4"
|
asgiref = ">=3.2.10,<4"
|
||||||
pytz = "*"
|
pytz = "*"
|
||||||
sqlparse = ">=0.2.2"
|
sqlparse = ">=0.2.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
argon2 = ["argon2-cffi (>=16.1.0)"]
|
||||||
|
bcrypt = ["bcrypt"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django-axes"
|
name = "django-axes"
|
||||||
version = "5.12.0"
|
version = "5.12.0"
|
||||||
|
|
@ -306,13 +304,13 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
rest_framework = ["djangorestframework (>=3.0.0)"]
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
django = ">=2.2"
|
django = ">=2.2"
|
||||||
pytz = "*"
|
pytz = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
rest_framework = ["djangorestframework (>=3.0.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "djangorestframework"
|
name = "djangorestframework"
|
||||||
version = "3.12.2"
|
version = "3.12.2"
|
||||||
|
|
@ -332,9 +330,6 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
validation = ["swagger-spec-validator (>=2.1.0)"]
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
coreapi = ">=2.3.3"
|
coreapi = ">=2.3.3"
|
||||||
coreschema = ">=0.0.4"
|
coreschema = ">=0.0.4"
|
||||||
|
|
@ -345,6 +340,9 @@ packaging = "*"
|
||||||
"ruamel.yaml" = ">=0.15.34"
|
"ruamel.yaml" = ">=0.15.34"
|
||||||
uritemplate = ">=3.0.0"
|
uritemplate = ">=3.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
validation = ["swagger-spec-validator (>=2.1.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "factory-boy"
|
name = "factory-boy"
|
||||||
version = "2.12.0"
|
version = "2.12.0"
|
||||||
|
|
@ -413,9 +411,6 @@ gevent = ["gevent (>=0.13)"]
|
||||||
setproctitle = ["setproctitle"]
|
setproctitle = ["setproctitle"]
|
||||||
tornado = ["tornado (>=0.2)"]
|
tornado = ["tornado (>=0.2)"]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
setuptools = ">=3.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "2.10"
|
version = "2.10"
|
||||||
|
|
@ -431,18 +426,14 @@ description = "Read metadata from Python packages"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
marker = "python_version < \"3.8\""
|
|
||||||
|
[package.dependencies]
|
||||||
|
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
||||||
|
zipp = ">=0.5"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||||
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
|
testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
zipp = ">=0.5"
|
|
||||||
|
|
||||||
[package.dependencies.typing-extensions]
|
|
||||||
version = ">=3.6.4"
|
|
||||||
python = "<3.8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inflection"
|
name = "inflection"
|
||||||
|
|
@ -482,12 +473,12 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
i18n = ["Babel (>=0.8)"]
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
MarkupSafe = ">=0.23"
|
MarkupSafe = ">=0.23"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
i18n = ["Babel (>=0.8)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kombu"
|
name = "kombu"
|
||||||
version = "4.6.11"
|
version = "4.6.11"
|
||||||
|
|
@ -496,6 +487,10 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
amqp = ">=2.6.0,<2.7"
|
||||||
|
importlib-metadata = {version = ">=0.18", markers = "python_version < \"3.8\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
azureservicebus = ["azure-servicebus (>=0.21.1)"]
|
azureservicebus = ["azure-servicebus (>=0.21.1)"]
|
||||||
azurestoragequeues = ["azure-storage-queue"]
|
azurestoragequeues = ["azure-storage-queue"]
|
||||||
|
|
@ -508,17 +503,10 @@ qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"]
|
||||||
redis = ["redis (>=3.3.11)"]
|
redis = ["redis (>=3.3.11)"]
|
||||||
slmq = ["softlayer-messaging (>=1.0.3)"]
|
slmq = ["softlayer-messaging (>=1.0.3)"]
|
||||||
sqlalchemy = ["sqlalchemy"]
|
sqlalchemy = ["sqlalchemy"]
|
||||||
sqs = ["boto3 (>=1.4.4)", "pycurl (7.43.0.2)"]
|
sqs = ["boto3 (>=1.4.4)", "pycurl (==7.43.0.2)"]
|
||||||
yaml = ["PyYAML (>=3.10)"]
|
yaml = ["PyYAML (>=3.10)"]
|
||||||
zookeeper = ["kazoo (>=1.3.1)"]
|
zookeeper = ["kazoo (>=1.3.1)"]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
amqp = ">=2.6.0,<2.7"
|
|
||||||
|
|
||||||
[package.dependencies.importlib-metadata]
|
|
||||||
version = ">=0.18"
|
|
||||||
python = "<3.8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lxml"
|
name = "lxml"
|
||||||
version = "4.6.2"
|
version = "4.6.2"
|
||||||
|
|
@ -597,13 +585,13 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
python-dateutil = "*"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
cron-description = ["cron-descriptor"]
|
cron-description = ["cron-descriptor"]
|
||||||
cron-schedule = ["croniter"]
|
cron-schedule = ["croniter"]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
python-dateutil = "*"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dateutil"
|
name = "python-dateutil"
|
||||||
version = "2.8.1"
|
version = "2.8.1"
|
||||||
|
|
@ -653,16 +641,16 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
|
|
||||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
certifi = ">=2017.4.17"
|
certifi = ">=2017.4.17"
|
||||||
chardet = ">=3.0.2,<5"
|
chardet = ">=3.0.2,<5"
|
||||||
idna = ">=2.5,<3"
|
idna = ">=2.5,<3"
|
||||||
urllib3 = ">=1.21.1,<1.27"
|
urllib3 = ">=1.21.1,<1.27"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests-oauthlib"
|
name = "requests-oauthlib"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
|
@ -671,13 +659,13 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
rsa = ["oauthlib (>=3.0.0)"]
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
oauthlib = ">=3.0.0"
|
oauthlib = ">=3.0.0"
|
||||||
requests = ">=2.0.0"
|
requests = ">=2.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruamel.yaml"
|
name = "ruamel.yaml"
|
||||||
version = "0.16.12"
|
version = "0.16.12"
|
||||||
|
|
@ -686,15 +674,13 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
"ruamel.yaml.clib" = {version = ">=0.1.2", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.9\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["ryd"]
|
docs = ["ryd"]
|
||||||
jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
|
jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
[package.dependencies."ruamel.yaml.clib"]
|
|
||||||
version = ">=0.1.2"
|
|
||||||
python = "<3.9"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruamel.yaml.clib"
|
name = "ruamel.yaml.clib"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|
@ -702,7 +688,6 @@ description = "C version of reader, parser and emitter for ruamel.yaml derived f
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
marker = "platform_python_implementation == \"CPython\" and python_version < \"3.9\""
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sentry-sdk"
|
name = "sentry-sdk"
|
||||||
|
|
@ -712,6 +697,10 @@ category = "main"
|
||||||
optional = true
|
optional = true
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
certifi = "*"
|
||||||
|
urllib3 = ">=1.10.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
aiohttp = ["aiohttp (>=3.5)"]
|
aiohttp = ["aiohttp (>=3.5)"]
|
||||||
beam = ["beam (>=2.12)"]
|
beam = ["beam (>=2.12)"]
|
||||||
|
|
@ -726,10 +715,6 @@ sanic = ["sanic (>=0.8)"]
|
||||||
sqlalchemy = ["sqlalchemy (>=1.2)"]
|
sqlalchemy = ["sqlalchemy (>=1.2)"]
|
||||||
tornado = ["tornado (>=5)"]
|
tornado = ["tornado (>=5)"]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
certifi = "*"
|
|
||||||
urllib3 = ">=1.10.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "six"
|
name = "six"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
|
|
@ -745,7 +730,6 @@ description = "A modern CSS selector implementation for Beautiful Soup."
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
marker = "python_version >= \"3.0\""
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlparse"
|
name = "sqlparse"
|
||||||
|
|
@ -786,7 +770,6 @@ description = "Backported and Experimental Type Hints for Python 3.5+"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
marker = "python_version < \"3.8\""
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uritemplate"
|
name = "uritemplate"
|
||||||
|
|
@ -807,7 +790,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||||
[package.extras]
|
[package.extras]
|
||||||
brotli = ["brotlipy (>=0.6.0)"]
|
brotli = ["brotlipy (>=0.6.0)"]
|
||||||
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
|
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vine"
|
name = "vine"
|
||||||
|
|
@ -840,17 +823,16 @@ description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
marker = "python_version < \"3.8\""
|
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
||||||
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||||
|
|
||||||
[extras]
|
[extras]
|
||||||
sentry = ["sentry-sdk"]
|
sentry = ["sentry-sdk"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.0"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.7"
|
python-versions = "^3.7"
|
||||||
content-hash = "051ae963128801a760a39a286257ec7d4faa8f1d8a47739fba80fdae6450002b"
|
content-hash = "051ae963128801a760a39a286257ec7d4faa8f1d8a47739fba80fdae6450002b"
|
||||||
|
|
||||||
|
|
@ -967,8 +949,8 @@ coverage = [
|
||||||
{file = "coverage-5.3.1.tar.gz", hash = "sha256:38f16b1317b8dd82df67ed5daa5f5e7c959e46579840d77a67a4ceb9cef0a50b"},
|
{file = "coverage-5.3.1.tar.gz", hash = "sha256:38f16b1317b8dd82df67ed5daa5f5e7c959e46579840d77a67a4ceb9cef0a50b"},
|
||||||
]
|
]
|
||||||
django = [
|
django = [
|
||||||
{file = "Django-3.1.5-py3-none-any.whl", hash = "sha256:efa2ab96b33b20c2182db93147a0c3cd7769d418926f9e9f140a60dca7c64ca9"},
|
{file = "Django-3.1.6-py3-none-any.whl", hash = "sha256:169e2e7b4839a7910b393eec127fd7cbae62e80fa55f89c6510426abf673fe5f"},
|
||||||
{file = "Django-3.1.5.tar.gz", hash = "sha256:2d78425ba74c7a1a74b196058b261b9733a8570782f4e2828974777ccca7edf7"},
|
{file = "Django-3.1.6.tar.gz", hash = "sha256:c6c0462b8b361f8691171af1fb87eceb4442da28477e12200c40420176206ba7"},
|
||||||
]
|
]
|
||||||
django-axes = [
|
django-axes = [
|
||||||
{file = "django-axes-5.12.0.tar.gz", hash = "sha256:c26167f7ca2003df8358eb23537dffb1d97bd9f44ccef70d5c64a7aba2349456"},
|
{file = "django-axes-5.12.0.tar.gz", hash = "sha256:c26167f7ca2003df8358eb23537dffb1d97bd9f44ccef70d5c64a7aba2349456"},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "newsreader"
|
name = "newsreader"
|
||||||
version = "0.2"
|
version = "0.3.9"
|
||||||
description = "Webapplication for reading RSS feeds"
|
description = "Webapplication for reading RSS feeds"
|
||||||
authors = ["Sonny <sonnyba871@gmail.com>"]
|
authors = ["Sonny <sonnyba871@gmail.com>"]
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from rest_framework.pagination import PageNumberPagination
|
from rest_framework import pagination
|
||||||
|
|
||||||
|
|
||||||
class ResultSetPagination(PageNumberPagination):
|
class ResultSetPagination(pagination.PageNumberPagination):
|
||||||
page_size_query_param = "count"
|
page_size_query_param = "count"
|
||||||
max_page_size = 50
|
max_page_size = 50
|
||||||
page_size = 30
|
page_size = 30
|
||||||
|
|
@ -10,3 +10,9 @@ class ResultSetPagination(PageNumberPagination):
|
||||||
class LargeResultSetPagination(ResultSetPagination):
|
class LargeResultSetPagination(ResultSetPagination):
|
||||||
max_page_size = 100
|
max_page_size = 100
|
||||||
page_size = 50
|
page_size = 50
|
||||||
|
|
||||||
|
|
||||||
|
class CursorPagination(pagination.CursorPagination):
|
||||||
|
page_size_query_param = "count"
|
||||||
|
ordering = "-publication_date"
|
||||||
|
page_size = 30
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ export const markPostRead = (post, token) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchPostsBySection = (section, page = false) => {
|
export const fetchPostsBySection = (section, next = false) => {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
if (section.unread === 0) {
|
if (section.unread === 0) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -76,10 +76,10 @@ export const fetchPostsBySection = (section, page = false) => {
|
||||||
|
|
||||||
switch (section.type) {
|
switch (section.type) {
|
||||||
case RULE_TYPE:
|
case RULE_TYPE:
|
||||||
url = page ? page : `/api/rules/${section.id}/posts/?read=false`;
|
url = next ? next : `/api/rules/${section.id}/posts/?read=false`;
|
||||||
break;
|
break;
|
||||||
case CATEGORY_TYPE:
|
case CATEGORY_TYPE:
|
||||||
url = page ? page : `/api/categories/${section.id}/posts/?read=false`;
|
url = next ? next : `/api/categories/${section.id}/posts/?read=false`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ const mapStateToProps = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
fetchPostsBySection: (rule, page = false) => dispatch(fetchPostsBySection(rule, page)),
|
fetchPostsBySection: (rule, next = false) => dispatch(fetchPostsBySection(rule, next)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(PostList);
|
export default connect(mapStateToProps, mapDispatchToProps)(PostList);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ if (page) {
|
||||||
const settings = JSON.parse(document.getElementById('homepageSettings').textContent);
|
const settings = JSON.parse(document.getElementById('homepageSettings').textContent);
|
||||||
const { feedUrl, subredditUrl, timelineUrl, categoriesUrl } = settings;
|
const { feedUrl, subredditUrl, timelineUrl, categoriesUrl } = settings;
|
||||||
|
|
||||||
ReactDOM.render(
|
const app = (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App
|
<App
|
||||||
feedUrl={feedUrl.substring(1, feedUrl.length - 3)}
|
feedUrl={feedUrl.substring(1, feedUrl.length - 3)}
|
||||||
|
|
@ -24,7 +24,8 @@ if (page) {
|
||||||
timezone={settings.timezone}
|
timezone={settings.timezone}
|
||||||
autoMarking={settings.autoMarking}
|
autoMarking={settings.autoMarking}
|
||||||
/>
|
/>
|
||||||
</Provider>,
|
</Provider>
|
||||||
page
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ReactDOM.render(app, page);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,16 @@ from rest_framework import status
|
||||||
from rest_framework.generics import (
|
from rest_framework.generics import (
|
||||||
GenericAPIView,
|
GenericAPIView,
|
||||||
ListAPIView,
|
ListAPIView,
|
||||||
RetrieveUpdateDestroyAPIView,
|
RetrieveUpdateAPIView,
|
||||||
get_object_or_404,
|
get_object_or_404,
|
||||||
)
|
)
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from newsreader.core.pagination import LargeResultSetPagination, ResultSetPagination
|
from newsreader.core.pagination import (
|
||||||
|
CursorPagination,
|
||||||
|
LargeResultSetPagination,
|
||||||
|
ResultSetPagination,
|
||||||
|
)
|
||||||
from newsreader.news.collection.models import CollectionRule
|
from newsreader.news.collection.models import CollectionRule
|
||||||
from newsreader.news.collection.serializers import RuleSerializer
|
from newsreader.news.collection.serializers import RuleSerializer
|
||||||
from newsreader.news.core.filters import ReadFilter
|
from newsreader.news.core.filters import ReadFilter
|
||||||
|
|
@ -15,26 +19,15 @@ from newsreader.news.core.models import Post
|
||||||
from newsreader.news.core.serializers import PostSerializer
|
from newsreader.news.core.serializers import PostSerializer
|
||||||
|
|
||||||
|
|
||||||
class ListRuleView(ListAPIView):
|
class DetailRuleView(RetrieveUpdateAPIView):
|
||||||
queryset = CollectionRule.objects.all()
|
queryset = CollectionRule.objects.all()
|
||||||
serializer_class = RuleSerializer
|
serializer_class = RuleSerializer
|
||||||
pagination_class = ResultSetPagination
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
user = self.request.user
|
|
||||||
return self.queryset.filter(user=user).order_by("-created")
|
|
||||||
|
|
||||||
|
|
||||||
class DetailRuleView(RetrieveUpdateDestroyAPIView):
|
|
||||||
queryset = CollectionRule.objects.all()
|
|
||||||
serializer_class = RuleSerializer
|
|
||||||
pagination_class = ResultSetPagination
|
|
||||||
|
|
||||||
|
|
||||||
class NestedRuleView(ListAPIView):
|
class NestedRuleView(ListAPIView):
|
||||||
queryset = CollectionRule.objects.prefetch_related("posts").all()
|
queryset = CollectionRule.objects.prefetch_related("posts").all()
|
||||||
serializer_class = PostSerializer
|
serializer_class = PostSerializer
|
||||||
pagination_class = LargeResultSetPagination
|
pagination_class = CursorPagination
|
||||||
filter_backends = [ReadFilter]
|
filter_backends = [ReadFilter]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
|
|
||||||
|
|
@ -121,15 +121,6 @@ class CollectionRuleDetailViewTestCase(TestCase):
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEquals(response.status_code, 200)
|
||||||
self.assertEquals(data["name"], "BBC")
|
self.assertEquals(data["name"], "BBC")
|
||||||
|
|
||||||
def test_delete(self):
|
|
||||||
rule = FeedFactory(user=self.user)
|
|
||||||
|
|
||||||
response = self.client.delete(
|
|
||||||
reverse("api:news:collection:rules-detail", args=[rule.pk])
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 204)
|
|
||||||
|
|
||||||
def test_rule_with_unauthenticated_user(self):
|
def test_rule_with_unauthenticated_user(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,137 +12,6 @@ from newsreader.news.collection.tests.factories import FeedFactory
|
||||||
from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
|
from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
|
||||||
|
|
||||||
|
|
||||||
class RuleListViewTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.user = UserFactory(password="test")
|
|
||||||
self.client.force_login(self.user)
|
|
||||||
|
|
||||||
def test_simple(self):
|
|
||||||
FeedFactory.create_batch(size=3, user=self.user)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:collection:rules-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
self.assertEquals(data["count"], 3)
|
|
||||||
|
|
||||||
def test_ordering(self):
|
|
||||||
rules = [
|
|
||||||
FeedFactory(
|
|
||||||
created=datetime.combine(
|
|
||||||
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
user=self.user,
|
|
||||||
),
|
|
||||||
FeedFactory(
|
|
||||||
created=datetime.combine(
|
|
||||||
date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
user=self.user,
|
|
||||||
),
|
|
||||||
FeedFactory(
|
|
||||||
created=datetime.combine(
|
|
||||||
date(2019, 7, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
user=self.user,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:collection:rules-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
self.assertEquals(data["count"], 3)
|
|
||||||
|
|
||||||
self.assertEquals(data["results"][0]["id"], rules[1].pk)
|
|
||||||
self.assertEquals(data["results"][1]["id"], rules[2].pk)
|
|
||||||
self.assertEquals(data["results"][2]["id"], rules[0].pk)
|
|
||||||
|
|
||||||
def test_pagination_count(self):
|
|
||||||
FeedFactory.create_batch(size=80, user=self.user)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("api:news:collection:rules-list"), {"count": 30}
|
|
||||||
)
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertEquals(data["count"], 80)
|
|
||||||
self.assertEquals(len(data["results"]), 30)
|
|
||||||
|
|
||||||
def test_empty(self):
|
|
||||||
response = self.client.get(reverse("api:news:collection:rules-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
|
|
||||||
self.assertEquals(data["count"], 0)
|
|
||||||
self.assertEquals(len(data["results"]), 0)
|
|
||||||
|
|
||||||
def test_post(self):
|
|
||||||
category = CategoryFactory(user=self.user)
|
|
||||||
|
|
||||||
data = {"name": "BBC", "url": "https://www.bbc.co.uk", "category": category.pk}
|
|
||||||
|
|
||||||
response = self.client.post(
|
|
||||||
reverse("api:news:collection:rules-list"),
|
|
||||||
data=json.dumps(data),
|
|
||||||
content_type="application/json",
|
|
||||||
)
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
|
||||||
self.assertEquals(data["detail"], 'Method "POST" not allowed.')
|
|
||||||
|
|
||||||
def test_patch(self):
|
|
||||||
response = self.client.patch(reverse("api:news:collection:rules-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
|
||||||
self.assertEquals(data["detail"], 'Method "PATCH" not allowed.')
|
|
||||||
|
|
||||||
def test_put(self):
|
|
||||||
response = self.client.put(reverse("api:news:collection:rules-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
|
||||||
self.assertEquals(data["detail"], 'Method "PUT" not allowed.')
|
|
||||||
|
|
||||||
def test_delete(self):
|
|
||||||
response = self.client.delete(reverse("api:news:collection:rules-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
|
||||||
self.assertEquals(data["detail"], 'Method "DELETE" not allowed.')
|
|
||||||
|
|
||||||
def test_rules_with_unauthenticated_user(self):
|
|
||||||
self.client.logout()
|
|
||||||
|
|
||||||
FeedFactory.create_batch(size=3, user=self.user)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:collection:rules-list"))
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
|
||||||
|
|
||||||
def test_rules_with_unauthorized_user(self):
|
|
||||||
other_user = UserFactory()
|
|
||||||
FeedFactory.create_batch(size=3, user=other_user)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:collection:rules-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
|
|
||||||
self.assertEquals(data["count"], 0)
|
|
||||||
self.assertEquals(len(data["results"]), 0)
|
|
||||||
|
|
||||||
|
|
||||||
class NestedRuleListViewTestCase(TestCase):
|
class NestedRuleListViewTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.user = UserFactory(password="test")
|
self.user = UserFactory(password="test")
|
||||||
|
|
@ -157,11 +26,10 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(len(data["results"]), 5)
|
||||||
self.assertTrue("results" in data)
|
self.assertEqual(data["next"], None)
|
||||||
self.assertTrue("count" in data)
|
self.assertEqual(data["previous"], None)
|
||||||
self.assertEquals(data["count"], 5)
|
|
||||||
|
|
||||||
def test_pagination(self):
|
def test_pagination(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
@ -178,11 +46,12 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 80)
|
self.assertTrue(data["next"])
|
||||||
self.assertEquals(len(data["results"]), 30)
|
self.assertFalse(data["previous"])
|
||||||
|
|
||||||
self.assertEquals(
|
self.assertEqual(len(data["results"]), 30)
|
||||||
|
self.assertEqual(
|
||||||
[post["id"] for post in data["results"]], [post.id for post in posts[:30]]
|
[post["id"] for post in data["results"]], [post.id for post in posts[:30]]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -194,16 +63,15 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 0)
|
self.assertEqual(len(data["results"]), 0)
|
||||||
self.assertEquals(len(data["results"]), 0)
|
|
||||||
|
|
||||||
def test_not_known(self):
|
def test_not_known(self):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": 0})
|
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": 0})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_post(self):
|
def test_post(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
@ -215,8 +83,8 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "POST" not allowed.')
|
self.assertEqual(data["detail"], 'Method "POST" not allowed.')
|
||||||
|
|
||||||
def test_patch(self):
|
def test_patch(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
@ -228,8 +96,8 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "PATCH" not allowed.')
|
self.assertEqual(data["detail"], 'Method "PATCH" not allowed.')
|
||||||
|
|
||||||
def test_put(self):
|
def test_put(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
@ -241,8 +109,8 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "PUT" not allowed.')
|
self.assertEqual(data["detail"], 'Method "PUT" not allowed.')
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
@ -254,8 +122,8 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "DELETE" not allowed.')
|
self.assertEqual(data["detail"], 'Method "DELETE" not allowed.')
|
||||||
|
|
||||||
def test_rule_with_unauthenticated_user(self):
|
def test_rule_with_unauthenticated_user(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
@ -266,7 +134,7 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
|
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
def test_rule_with_unauthorized_user(self):
|
def test_rule_with_unauthorized_user(self):
|
||||||
other_user = UserFactory()
|
other_user = UserFactory()
|
||||||
|
|
@ -276,7 +144,7 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
|
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
def test_posts_ordering(self):
|
def test_posts_ordering(self):
|
||||||
rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
|
rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
|
||||||
|
|
@ -310,14 +178,12 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertTrue("results" in data)
|
self.assertEqual(len(data["results"]), 3)
|
||||||
self.assertTrue("count" in data)
|
|
||||||
self.assertEquals(data["count"], 3)
|
|
||||||
|
|
||||||
self.assertEquals(data["results"][0]["id"], posts[1].pk)
|
self.assertEqual(data["results"][0]["id"], posts[1].pk)
|
||||||
self.assertEquals(data["results"][1]["id"], posts[2].pk)
|
self.assertEqual(data["results"][1]["id"], posts[2].pk)
|
||||||
self.assertEquals(data["results"][2]["id"], posts[0].pk)
|
self.assertEqual(data["results"][2]["id"], posts[0].pk)
|
||||||
|
|
||||||
def test_only_posts_from_rule_are_returned(self):
|
def test_only_posts_from_rule_are_returned(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
@ -331,14 +197,12 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(len(data["results"]), 5)
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
self.assertEquals(data["count"], 5)
|
|
||||||
|
|
||||||
for post in data["results"]:
|
for post in data["results"]:
|
||||||
self.assertEquals(post["rule"], rule.pk)
|
with self.subTest(post=post):
|
||||||
|
self.assertEqual(post["rule"], rule.pk)
|
||||||
|
|
||||||
def test_unread_posts(self):
|
def test_unread_posts(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
@ -352,13 +216,13 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 10)
|
self.assertEqual(len(data["results"]), 10)
|
||||||
|
|
||||||
for post in posts:
|
for post in data["results"]:
|
||||||
self.assertEquals(post["read"], False)
|
with self.subTest(post=post):
|
||||||
|
self.assertEqual(post["read"], False)
|
||||||
|
|
||||||
def test_read_posts(self):
|
def test_read_posts(self):
|
||||||
rule = FeedFactory.create(user=self.user)
|
rule = FeedFactory.create(user=self.user)
|
||||||
|
|
@ -372,10 +236,10 @@ class NestedRuleListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 10)
|
self.assertEqual(len(data["results"]), 10)
|
||||||
|
|
||||||
for post in posts:
|
for post in data["results"]:
|
||||||
self.assertEquals(post["read"], True)
|
with self.subTest(post=post):
|
||||||
|
self.assertEqual(post["read"], True)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ from django.urls import path
|
||||||
|
|
||||||
from newsreader.news.collection.endpoints import (
|
from newsreader.news.collection.endpoints import (
|
||||||
DetailRuleView,
|
DetailRuleView,
|
||||||
ListRuleView,
|
|
||||||
NestedRuleView,
|
NestedRuleView,
|
||||||
RuleReadView,
|
RuleReadView,
|
||||||
)
|
)
|
||||||
|
|
@ -26,7 +25,6 @@ endpoints = [
|
||||||
path("rules/<int:pk>/", DetailRuleView.as_view(), name="rules-detail"),
|
path("rules/<int:pk>/", DetailRuleView.as_view(), name="rules-detail"),
|
||||||
path("rules/<int:pk>/posts/", NestedRuleView.as_view(), name="rules-nested-posts"),
|
path("rules/<int:pk>/posts/", NestedRuleView.as_view(), name="rules-nested-posts"),
|
||||||
path("rules/<int:pk>/read/", RuleReadView.as_view(), name="rules-read"),
|
path("rules/<int:pk>/read/", RuleReadView.as_view(), name="rules-read"),
|
||||||
path("rules/", ListRuleView.as_view(), name="rules-list"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
from django.db.models import Q
|
|
||||||
|
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.generics import (
|
from rest_framework.generics import (
|
||||||
GenericAPIView,
|
GenericAPIView,
|
||||||
|
|
@ -13,30 +11,13 @@ from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from newsreader.accounts.permissions import IsPostOwner
|
from newsreader.accounts.permissions import IsPostOwner
|
||||||
from newsreader.core.pagination import LargeResultSetPagination
|
from newsreader.core.pagination import CursorPagination
|
||||||
from newsreader.news.collection.serializers import RuleSerializer
|
from newsreader.news.collection.serializers import RuleSerializer
|
||||||
from newsreader.news.core.filters import ReadFilter
|
from newsreader.news.core.filters import ReadFilter
|
||||||
from newsreader.news.core.models import Category, Post
|
from newsreader.news.core.models import Category, Post
|
||||||
from newsreader.news.core.serializers import CategorySerializer, PostSerializer
|
from newsreader.news.core.serializers import CategorySerializer, PostSerializer
|
||||||
|
|
||||||
|
|
||||||
class ListPostView(ListAPIView):
|
|
||||||
queryset = Post.objects.all()
|
|
||||||
serializer_class = PostSerializer
|
|
||||||
pagination_class = LargeResultSetPagination
|
|
||||||
filter_backends = [ReadFilter]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
user = self.request.user
|
|
||||||
queryset = (
|
|
||||||
self.queryset.filter(rule__user=user)
|
|
||||||
.filter(Q(rule__category=None) | Q(rule__category__user=user))
|
|
||||||
.order_by("rule", "-publication_date", "-created")
|
|
||||||
)
|
|
||||||
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
|
|
||||||
class DetailPostView(RetrieveUpdateAPIView):
|
class DetailPostView(RetrieveUpdateAPIView):
|
||||||
queryset = Post.objects.all()
|
queryset = Post.objects.all()
|
||||||
serializer_class = PostSerializer
|
serializer_class = PostSerializer
|
||||||
|
|
@ -77,7 +58,7 @@ class NestedRuleCategoryView(ListAPIView):
|
||||||
class NestedPostCategoryView(ListAPIView):
|
class NestedPostCategoryView(ListAPIView):
|
||||||
queryset = Category.objects.prefetch_related("rules", "rules__posts").all()
|
queryset = Category.objects.prefetch_related("rules", "rules__posts").all()
|
||||||
serializer_class = PostSerializer
|
serializer_class = PostSerializer
|
||||||
pagination_class = LargeResultSetPagination
|
pagination_class = CursorPagination
|
||||||
filter_backends = [ReadFilter]
|
filter_backends = [ReadFilter]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
|
@ -90,9 +71,8 @@ class NestedPostCategoryView(ListAPIView):
|
||||||
category = get_object_or_404(self.queryset, **filter_kwargs)
|
category = get_object_or_404(self.queryset, **filter_kwargs)
|
||||||
self.check_object_permissions(self.request, category)
|
self.check_object_permissions(self.request, category)
|
||||||
|
|
||||||
queryset = Post.objects.filter(
|
rules = category.rules.values_list("id", flat=True)
|
||||||
rule__in=category.rules.values_list("id", flat=True)
|
queryset = Post.objects.filter(rule__in=rules)
|
||||||
).order_by("-publication_date", "rule__name")
|
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from datetime import date, datetime, time
|
from datetime import datetime
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
@ -23,27 +23,21 @@ class CategoryListViewTestCase(TestCase):
|
||||||
response = self.client.get(reverse("api:news:core:categories-list"))
|
response = self.client.get(reverse("api:news:core:categories-list"))
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(len(data), 3)
|
self.assertEqual(len(data), 3)
|
||||||
|
|
||||||
def test_ordering(self):
|
def test_ordering(self):
|
||||||
categories = [
|
categories = [
|
||||||
CategoryFactory(
|
CategoryFactory(
|
||||||
created=datetime.combine(
|
created=datetime(2019, 5, 20, 16, 7, 37, tzinfo=pytz.utc),
|
||||||
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
user=self.user,
|
user=self.user,
|
||||||
),
|
),
|
||||||
CategoryFactory(
|
CategoryFactory(
|
||||||
created=datetime.combine(
|
created=datetime(2019, 7, 20, 18, 7, 37, tzinfo=pytz.utc),
|
||||||
date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
user=self.user,
|
user=self.user,
|
||||||
),
|
),
|
||||||
CategoryFactory(
|
CategoryFactory(
|
||||||
created=datetime.combine(
|
created=datetime(2019, 7, 20, 16, 7, 37, tzinfo=pytz.utc),
|
||||||
date(2019, 7, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
user=self.user,
|
user=self.user,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
@ -51,18 +45,18 @@ class CategoryListViewTestCase(TestCase):
|
||||||
response = self.client.get(reverse("api:news:core:categories-list"))
|
response = self.client.get(reverse("api:news:core:categories-list"))
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
self.assertEquals(data[0]["id"], categories[1].pk)
|
self.assertEqual(data[0]["id"], categories[1].pk)
|
||||||
self.assertEquals(data[1]["id"], categories[2].pk)
|
self.assertEqual(data[1]["id"], categories[2].pk)
|
||||||
self.assertEquals(data[2]["id"], categories[0].pk)
|
self.assertEqual(data[2]["id"], categories[0].pk)
|
||||||
|
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
response = self.client.get(reverse("api:news:core:categories-list"))
|
response = self.client.get(reverse("api:news:core:categories-list"))
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(len(data), 0)
|
self.assertEqual(len(data), 0)
|
||||||
|
|
||||||
def test_post(self):
|
def test_post(self):
|
||||||
data = {"name": "Tech"}
|
data = {"name": "Tech"}
|
||||||
|
|
@ -74,29 +68,29 @@ class CategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
response_data = response.json()
|
response_data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(response_data["detail"], 'Method "POST" not allowed.')
|
self.assertEqual(response_data["detail"], 'Method "POST" not allowed.')
|
||||||
|
|
||||||
def test_patch(self):
|
def test_patch(self):
|
||||||
response = self.client.patch(reverse("api:news:core:categories-list"))
|
response = self.client.patch(reverse("api:news:core:categories-list"))
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "PATCH" not allowed.')
|
self.assertEqual(data["detail"], 'Method "PATCH" not allowed.')
|
||||||
|
|
||||||
def test_put(self):
|
def test_put(self):
|
||||||
response = self.client.put(reverse("api:news:core:categories-list"))
|
response = self.client.put(reverse("api:news:core:categories-list"))
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "PUT" not allowed.')
|
self.assertEqual(data["detail"], 'Method "PUT" not allowed.')
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
response = self.client.delete(reverse("api:news:core:categories-list"))
|
response = self.client.delete(reverse("api:news:core:categories-list"))
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "DELETE" not allowed.')
|
self.assertEqual(data["detail"], 'Method "DELETE" not allowed.')
|
||||||
|
|
||||||
def test_categories_with_unauthenticated_user(self):
|
def test_categories_with_unauthenticated_user(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
@ -105,7 +99,7 @@ class CategoryListViewTestCase(TestCase):
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:categories-list"))
|
response = self.client.get(reverse("api:news:core:categories-list"))
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
def test_categories_with_unauthorized_user(self):
|
def test_categories_with_unauthorized_user(self):
|
||||||
other_user = UserFactory()
|
other_user = UserFactory()
|
||||||
|
|
@ -114,8 +108,8 @@ class CategoryListViewTestCase(TestCase):
|
||||||
response = self.client.get(reverse("api:news:core:categories-list"))
|
response = self.client.get(reverse("api:news:core:categories-list"))
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(len(data), 0)
|
self.assertEqual(len(data), 0)
|
||||||
|
|
||||||
|
|
||||||
class NestedCategoryListViewTestCase(TestCase):
|
class NestedCategoryListViewTestCase(TestCase):
|
||||||
|
|
@ -132,8 +126,8 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(len(data), 5)
|
self.assertEqual(len(data), 5)
|
||||||
|
|
||||||
self.assertTrue("id" in data[0])
|
self.assertTrue("id" in data[0])
|
||||||
self.assertTrue("name" in data[0])
|
self.assertTrue("name" in data[0])
|
||||||
|
|
@ -149,16 +143,16 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(len(data), 0)
|
self.assertEqual(len(data), 0)
|
||||||
self.assertEquals(data, [])
|
self.assertEqual(data, [])
|
||||||
|
|
||||||
def test_not_known(self):
|
def test_not_known(self):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse("api:news:core:categories-nested-rules", kwargs={"pk": 100})
|
reverse("api:news:core:categories-nested-rules", kwargs={"pk": 100})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_post(self):
|
def test_post(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
|
|
@ -168,8 +162,8 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "POST" not allowed.')
|
self.assertEqual(data["detail"], 'Method "POST" not allowed.')
|
||||||
|
|
||||||
def test_patch(self):
|
def test_patch(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -183,8 +177,8 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "PATCH" not allowed.')
|
self.assertEqual(data["detail"], 'Method "PATCH" not allowed.')
|
||||||
|
|
||||||
def test_put(self):
|
def test_put(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -198,8 +192,8 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "PUT" not allowed.')
|
self.assertEqual(data["detail"], 'Method "PUT" not allowed.')
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -212,8 +206,8 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "DELETE" not allowed.')
|
self.assertEqual(data["detail"], 'Method "DELETE" not allowed.')
|
||||||
|
|
||||||
def test_with_unauthenticated_user(self):
|
def test_with_unauthenticated_user(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
@ -225,7 +219,7 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk})
|
reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
def test_with_unauthorized_user(self):
|
def test_with_unauthorized_user(self):
|
||||||
other_user = UserFactory.create()
|
other_user = UserFactory.create()
|
||||||
|
|
@ -237,7 +231,7 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk})
|
reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
def test_ordering(self):
|
def test_ordering(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -252,12 +246,12 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(len(data), 3)
|
self.assertEqual(len(data), 3)
|
||||||
|
|
||||||
self.assertEquals(data[0]["id"], rules[2].pk)
|
self.assertEqual(data[0]["id"], rules[2].pk)
|
||||||
self.assertEquals(data[1]["id"], rules[0].pk)
|
self.assertEqual(data[1]["id"], rules[0].pk)
|
||||||
self.assertEquals(data[2]["id"], rules[1].pk)
|
self.assertEqual(data[2]["id"], rules[1].pk)
|
||||||
|
|
||||||
def test_only_rules_from_category_are_returned(self):
|
def test_only_rules_from_category_are_returned(self):
|
||||||
other_category = CategoryFactory(user=self.user)
|
other_category = CategoryFactory(user=self.user)
|
||||||
|
|
@ -275,12 +269,12 @@ class NestedCategoryListViewTestCase(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(len(data), 3)
|
self.assertEqual(len(data), 3)
|
||||||
|
|
||||||
self.assertEquals(data[0]["id"], rules[2].pk)
|
self.assertEqual(data[0]["id"], rules[2].pk)
|
||||||
self.assertEquals(data[1]["id"], rules[0].pk)
|
self.assertEqual(data[1]["id"], rules[0].pk)
|
||||||
self.assertEquals(data[2]["id"], rules[1].pk)
|
self.assertEqual(data[2]["id"], rules[1].pk)
|
||||||
|
|
||||||
|
|
||||||
class NestedCategoryPostView(TestCase):
|
class NestedCategoryPostView(TestCase):
|
||||||
|
|
@ -301,16 +295,15 @@ class NestedCategoryPostView(TestCase):
|
||||||
reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk})
|
reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk})
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 25)
|
self.assertEqual(len(data["results"]), 25)
|
||||||
|
|
||||||
self.assertTrue("id" in posts[0])
|
self.assertTrue("id" in data["results"][0])
|
||||||
self.assertTrue("title" in posts[0])
|
self.assertTrue("title" in data["results"][0])
|
||||||
self.assertTrue("body" in posts[0])
|
self.assertTrue("body" in data["results"][0])
|
||||||
self.assertTrue("rule" in posts[0])
|
self.assertTrue("rule" in data["results"][0])
|
||||||
self.assertTrue("url" in posts[0])
|
self.assertTrue("url" in data["results"][0])
|
||||||
|
|
||||||
def test_no_rules(self):
|
def test_no_rules(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -321,9 +314,9 @@ class NestedCategoryPostView(TestCase):
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
posts = data["results"]
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 0)
|
self.assertEqual(len(data["results"]), 0)
|
||||||
self.assertEquals(posts, [])
|
self.assertEqual(posts, [])
|
||||||
|
|
||||||
def test_no_posts(self):
|
def test_no_posts(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -335,16 +328,16 @@ class NestedCategoryPostView(TestCase):
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
posts = data["results"]
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 0)
|
self.assertEqual(len(data["results"]), 0)
|
||||||
self.assertEquals(posts, [])
|
self.assertEqual(posts, [])
|
||||||
|
|
||||||
def test_not_known(self):
|
def test_not_known(self):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse("api:news:core:categories-nested-posts", kwargs={"pk": 100})
|
reverse("api:news:core:categories-nested-posts", kwargs={"pk": 100})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_post(self):
|
def test_post(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
|
|
@ -354,8 +347,8 @@ class NestedCategoryPostView(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "POST" not allowed.')
|
self.assertEqual(data["detail"], 'Method "POST" not allowed.')
|
||||||
|
|
||||||
def test_patch(self):
|
def test_patch(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -369,8 +362,8 @@ class NestedCategoryPostView(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "PATCH" not allowed.')
|
self.assertEqual(data["detail"], 'Method "PATCH" not allowed.')
|
||||||
|
|
||||||
def test_put(self):
|
def test_put(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -384,8 +377,8 @@ class NestedCategoryPostView(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "PUT" not allowed.')
|
self.assertEqual(data["detail"], 'Method "PUT" not allowed.')
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -398,8 +391,8 @@ class NestedCategoryPostView(TestCase):
|
||||||
)
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
self.assertEquals(data["detail"], 'Method "DELETE" not allowed.')
|
self.assertEqual(data["detail"], 'Method "DELETE" not allowed.')
|
||||||
|
|
||||||
def test_with_unauthenticated_user(self):
|
def test_with_unauthenticated_user(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
@ -410,7 +403,7 @@ class NestedCategoryPostView(TestCase):
|
||||||
reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk})
|
reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
def test_with_unauthorized_user(self):
|
def test_with_unauthorized_user(self):
|
||||||
other_user = UserFactory.create()
|
other_user = UserFactory.create()
|
||||||
|
|
@ -420,7 +413,7 @@ class NestedCategoryPostView(TestCase):
|
||||||
reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk})
|
reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk})
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
def test_ordering(self):
|
def test_ordering(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -437,16 +430,12 @@ class NestedCategoryPostView(TestCase):
|
||||||
FeedPostFactory.create(
|
FeedPostFactory.create(
|
||||||
title="Second Reuters post",
|
title="Second Reuters post",
|
||||||
rule=reuters_rule,
|
rule=reuters_rule,
|
||||||
publication_date=datetime.combine(
|
publication_date=datetime(2019, 5, 21, 15, tzinfo=pytz.utc),
|
||||||
date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
FeedPostFactory.create(
|
FeedPostFactory.create(
|
||||||
title="First Reuters post",
|
title="First Reuters post",
|
||||||
rule=reuters_rule,
|
rule=reuters_rule,
|
||||||
publication_date=datetime.combine(
|
publication_date=datetime(2019, 5, 20, 12, tzinfo=pytz.utc),
|
||||||
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -454,16 +443,12 @@ class NestedCategoryPostView(TestCase):
|
||||||
FeedPostFactory.create(
|
FeedPostFactory.create(
|
||||||
title="Second Guardian post",
|
title="Second Guardian post",
|
||||||
rule=guardian_rule,
|
rule=guardian_rule,
|
||||||
publication_date=datetime.combine(
|
publication_date=datetime(2019, 5, 21, 14, tzinfo=pytz.utc),
|
||||||
date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
FeedPostFactory.create(
|
FeedPostFactory.create(
|
||||||
title="First Guardian post",
|
title="First Guardian post",
|
||||||
rule=guardian_rule,
|
rule=guardian_rule,
|
||||||
publication_date=datetime.combine(
|
publication_date=datetime(2019, 5, 20, 11, tzinfo=pytz.utc),
|
||||||
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -471,16 +456,12 @@ class NestedCategoryPostView(TestCase):
|
||||||
FeedPostFactory.create(
|
FeedPostFactory.create(
|
||||||
title="Second BBC post",
|
title="Second BBC post",
|
||||||
rule=bbc_rule,
|
rule=bbc_rule,
|
||||||
publication_date=datetime.combine(
|
publication_date=datetime(2019, 5, 21, 16, tzinfo=pytz.utc),
|
||||||
date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
FeedPostFactory.create(
|
FeedPostFactory.create(
|
||||||
title="First BBC post",
|
title="First BBC post",
|
||||||
rule=bbc_rule,
|
rule=bbc_rule,
|
||||||
publication_date=datetime.combine(
|
publication_date=datetime(2019, 5, 20, 13, tzinfo=pytz.utc),
|
||||||
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -490,16 +471,16 @@ class NestedCategoryPostView(TestCase):
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
posts = data["results"]
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 6)
|
self.assertEqual(len(data["results"]), 6)
|
||||||
|
|
||||||
self.assertEquals(posts[0]["title"], "Second BBC post")
|
self.assertEqual(posts[0]["title"], "Second BBC post")
|
||||||
self.assertEquals(posts[1]["title"], "Second Reuters post")
|
self.assertEqual(posts[1]["title"], "Second Reuters post")
|
||||||
self.assertEquals(posts[2]["title"], "Second Guardian post")
|
self.assertEqual(posts[2]["title"], "Second Guardian post")
|
||||||
|
|
||||||
self.assertEquals(posts[3]["title"], "First BBC post")
|
self.assertEqual(posts[3]["title"], "First BBC post")
|
||||||
self.assertEquals(posts[4]["title"], "First Reuters post")
|
self.assertEqual(posts[4]["title"], "First Reuters post")
|
||||||
self.assertEquals(posts[5]["title"], "First Guardian post")
|
self.assertEqual(posts[5]["title"], "First Guardian post")
|
||||||
|
|
||||||
def test_only_posts_from_category_are_returned(self):
|
def test_only_posts_from_category_are_returned(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -526,11 +507,11 @@ class NestedCategoryPostView(TestCase):
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
posts = data["results"]
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 2)
|
self.assertEqual(len(data["results"]), 2)
|
||||||
|
|
||||||
self.assertEquals(posts[0]["rule"], guardian_rule.pk)
|
self.assertEqual(posts[0]["rule"], guardian_rule.pk)
|
||||||
self.assertEquals(posts[1]["rule"], guardian_rule.pk)
|
self.assertEqual(posts[1]["rule"], guardian_rule.pk)
|
||||||
|
|
||||||
def test_unread_posts(self):
|
def test_unread_posts(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -549,11 +530,11 @@ class NestedCategoryPostView(TestCase):
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
posts = data["results"]
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 10)
|
self.assertEqual(len(data["results"]), 10)
|
||||||
|
|
||||||
for post in posts:
|
for post in posts:
|
||||||
self.assertEquals(post["read"], False)
|
self.assertEqual(post["read"], False)
|
||||||
|
|
||||||
def test_read_posts(self):
|
def test_read_posts(self):
|
||||||
category = CategoryFactory.create(user=self.user)
|
category = CategoryFactory.create(user=self.user)
|
||||||
|
|
@ -572,8 +553,8 @@ class NestedCategoryPostView(TestCase):
|
||||||
data = response.json()
|
data = response.json()
|
||||||
posts = data["results"]
|
posts = data["results"]
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEquals(data["count"], 10)
|
self.assertEqual(len(data["results"]), 10)
|
||||||
|
|
||||||
for post in posts:
|
for post in posts:
|
||||||
self.assertEquals(post["read"], True)
|
self.assertEqual(post["read"], True)
|
||||||
|
|
|
||||||
|
|
@ -1,234 +0,0 @@
|
||||||
from datetime import date, datetime, time
|
|
||||||
|
|
||||||
from django.test import TestCase
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
import pytz
|
|
||||||
|
|
||||||
from newsreader.accounts.tests.factories import UserFactory
|
|
||||||
from newsreader.news.collection.tests.factories import FeedFactory
|
|
||||||
from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
|
|
||||||
|
|
||||||
|
|
||||||
class PostListViewTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.user = UserFactory(is_staff=True, password="test")
|
|
||||||
self.client.force_login(self.user)
|
|
||||||
|
|
||||||
def test_simple(self):
|
|
||||||
rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
|
|
||||||
FeedPostFactory.create_batch(size=3, rule=rule)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
self.assertEquals(data["count"], 3)
|
|
||||||
|
|
||||||
def test_ordering(self):
|
|
||||||
rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
|
|
||||||
|
|
||||||
posts = [
|
|
||||||
FeedPostFactory(
|
|
||||||
title="I'm the first post",
|
|
||||||
rule=rule,
|
|
||||||
publication_date=datetime.combine(
|
|
||||||
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FeedPostFactory(
|
|
||||||
title="I'm the second post",
|
|
||||||
rule=rule,
|
|
||||||
publication_date=datetime.combine(
|
|
||||||
date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FeedPostFactory(
|
|
||||||
title="I'm the third post",
|
|
||||||
rule=rule,
|
|
||||||
publication_date=datetime.combine(
|
|
||||||
date(2019, 7, 20), time(hour=16, minute=7, second=37), pytz.utc
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
self.assertEquals(data["count"], 3)
|
|
||||||
|
|
||||||
self.assertEquals(data["results"][0]["id"], posts[1].pk)
|
|
||||||
self.assertEquals(data["results"][1]["id"], posts[2].pk)
|
|
||||||
self.assertEquals(data["results"][2]["id"], posts[0].pk)
|
|
||||||
|
|
||||||
def test_pagination_count(self):
|
|
||||||
rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
|
|
||||||
FeedPostFactory.create_batch(size=80, rule=rule)
|
|
||||||
page_size = 50
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"), {"count": 50})
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertEquals(data["count"], 80)
|
|
||||||
self.assertEquals(len(data["results"]), page_size)
|
|
||||||
|
|
||||||
def test_empty(self):
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
|
|
||||||
self.assertEquals(data["count"], 0)
|
|
||||||
self.assertEquals(len(data["results"]), 0)
|
|
||||||
|
|
||||||
def test_post(self):
|
|
||||||
response = self.client.post(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
|
||||||
self.assertEquals(data["detail"], 'Method "POST" not allowed.')
|
|
||||||
|
|
||||||
def test_patch(self):
|
|
||||||
response = self.client.patch(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
|
||||||
self.assertEquals(data["detail"], 'Method "PATCH" not allowed.')
|
|
||||||
|
|
||||||
def test_put(self):
|
|
||||||
response = self.client.put(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
|
||||||
self.assertEquals(data["detail"], 'Method "PUT" not allowed.')
|
|
||||||
|
|
||||||
def test_delete(self):
|
|
||||||
response = self.client.delete(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
|
||||||
self.assertEquals(data["detail"], 'Method "DELETE" not allowed.')
|
|
||||||
|
|
||||||
def test_posts_with_unauthenticated_user_without_category(self):
|
|
||||||
self.client.logout()
|
|
||||||
|
|
||||||
FeedPostFactory.create_batch(size=3, rule=FeedFactory(user=self.user))
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
|
||||||
|
|
||||||
def test_posts_with_unauthenticated_user_with_category(self):
|
|
||||||
self.client.logout()
|
|
||||||
|
|
||||||
category = CategoryFactory(user=self.user)
|
|
||||||
|
|
||||||
FeedPostFactory.create_batch(
|
|
||||||
size=3, rule=FeedFactory(user=self.user, category=category)
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 403)
|
|
||||||
|
|
||||||
def test_posts_with_unauthorized_user_without_category(self):
|
|
||||||
other_user = UserFactory()
|
|
||||||
|
|
||||||
rule = FeedFactory(user=other_user, category=None)
|
|
||||||
FeedPostFactory.create_batch(size=3, rule=rule)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertEquals(len(data["results"]), 0)
|
|
||||||
self.assertEquals(data["count"], 0)
|
|
||||||
|
|
||||||
def test_posts_with_unauthorized_user_with_category(self):
|
|
||||||
other_user = UserFactory()
|
|
||||||
category = CategoryFactory(user=other_user)
|
|
||||||
|
|
||||||
FeedPostFactory.create_batch(
|
|
||||||
size=3, rule=FeedFactory(user=other_user, category=category)
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertEquals(len(data["results"]), 0)
|
|
||||||
self.assertEquals(data["count"], 0)
|
|
||||||
|
|
||||||
# Note that this situation should not be possible, due to the user not being able
|
|
||||||
# to specify the user when creating categories/rules
|
|
||||||
def test_posts_with_authorized_rule_unauthorized_category(self):
|
|
||||||
other_user = UserFactory()
|
|
||||||
|
|
||||||
rule = FeedFactory(user=self.user, category=CategoryFactory(user=other_user))
|
|
||||||
FeedPostFactory.create_batch(size=3, rule=rule)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
self.assertEquals(data["count"], 0)
|
|
||||||
|
|
||||||
def test_posts_with_authorized_user_without_category(self):
|
|
||||||
rule = FeedFactory(user=self.user, category=None)
|
|
||||||
FeedPostFactory.create_batch(size=3, rule=rule)
|
|
||||||
|
|
||||||
response = self.client.get(reverse("api:news:core:posts-list"))
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertTrue("results" in data)
|
|
||||||
self.assertTrue("count" in data)
|
|
||||||
self.assertEquals(data["count"], 3)
|
|
||||||
|
|
||||||
def test_unread_posts(self):
|
|
||||||
rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
|
|
||||||
|
|
||||||
FeedPostFactory.create_batch(size=10, rule=rule, read=False)
|
|
||||||
FeedPostFactory.create_batch(size=10, rule=rule, read=True)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("api:news:core:posts-list"), {"read": "false"}
|
|
||||||
)
|
|
||||||
|
|
||||||
data = response.json()
|
|
||||||
posts = data["results"]
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertEquals(data["count"], 10)
|
|
||||||
|
|
||||||
for post in posts:
|
|
||||||
self.assertEquals(post["read"], False)
|
|
||||||
|
|
||||||
def test_read_posts(self):
|
|
||||||
rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
|
|
||||||
|
|
||||||
FeedPostFactory.create_batch(size=20, rule=rule, read=False)
|
|
||||||
FeedPostFactory.create_batch(size=10, rule=rule, read=True)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("api:news:core:posts-list"), {"read": "true"}
|
|
||||||
)
|
|
||||||
|
|
||||||
data = response.json()
|
|
||||||
posts = data["results"]
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
self.assertEquals(data["count"], 10)
|
|
||||||
|
|
||||||
for post in posts:
|
|
||||||
self.assertEquals(post["read"], True)
|
|
||||||
|
|
@ -6,7 +6,6 @@ from newsreader.news.core.endpoints import (
|
||||||
DetailCategoryView,
|
DetailCategoryView,
|
||||||
DetailPostView,
|
DetailPostView,
|
||||||
ListCategoryView,
|
ListCategoryView,
|
||||||
ListPostView,
|
|
||||||
NestedPostCategoryView,
|
NestedPostCategoryView,
|
||||||
NestedRuleCategoryView,
|
NestedRuleCategoryView,
|
||||||
)
|
)
|
||||||
|
|
@ -33,7 +32,6 @@ urlpatterns = [
|
||||||
]
|
]
|
||||||
|
|
||||||
endpoints = [
|
endpoints = [
|
||||||
path("posts/", ListPostView.as_view(), name="posts-list"),
|
|
||||||
path("posts/<int:pk>/", DetailPostView.as_view(), name="posts-detail"),
|
path("posts/<int:pk>/", DetailPostView.as_view(), name="posts-detail"),
|
||||||
path("categories/", ListCategoryView.as_view(), name="categories-list"),
|
path("categories/", ListCategoryView.as_view(), name="categories-list"),
|
||||||
path(
|
path(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue