Compare commits

...
Sign in to create a new pull request.

12 commits

50 changed files with 11613 additions and 16845 deletions

View file

@ -1,11 +0,0 @@
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-transform-runtime",
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-transform-react-jsx",
"@babel/plugin-syntax-function-bind",
"@babel/plugin-proposal-function-bind",
["@babel/plugin-proposal-class-properties", {loose: true}],
]
}

View file

@ -1,5 +1,17 @@
# Changelog
## 0.5.0
- Require python 3.11
- Require node 18 (current LTS)
- Upgrade webpack 4 -> 5
- Updated python dependencies
- `django` `3.2` -> `4.2`
- `psycopg` `2.9.x` -> `3.1.x`
- `python-dotenv` `2.9.x` -> `3.1.x`
- migrated from `python-memcached` to `pymemcache`
- removed `drf-yasg`
## 0.4.2
- Set `SECURE_PROXY_SSL_HEADER` setting for production

12
babel.config.js Normal file
View file

@ -0,0 +1,12 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-react',
],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-syntax-function-bind',
'@babel/plugin-proposal-function-bind',
['@babel/plugin-proposal-class-properties', { loose: true }],
],
};

View file

@ -1,5 +1,5 @@
# stage 1
FROM python:3.9-bullseye as backend
FROM python:3.11-bookworm as backend
RUN apt-get update && apt-get install -y --no-install-recommends \
vim \
@ -18,7 +18,7 @@ RUN pip install -r requirements/base.txt
# stage 2
FROM node:16-bullseye AS frontend-build
FROM node:lts-bookworm AS frontend-build
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
@ -28,15 +28,15 @@ WORKDIR /app
COPY ./*.json ./*.js ./.babelrc /app/
RUN npm ci
RUN npm ci --include=dev
COPY ./src /app/src
RUN npm run build
RUN npm run build:prod
# stage 3
FROM python:3.9-bullseye as production
FROM python:3.11-bookworm as production
RUN apt-get update && apt-get install -y --no-install-recommends \
postgresql-client \
@ -51,7 +51,7 @@ RUN mkdir /app/logs
RUN mkdir /app/media
RUN mkdir /app/bin
COPY --from=backend /usr/local/lib/python3.9 /usr/local/lib/python3.9
COPY --from=backend /usr/local/lib/python3.11 /usr/local/lib/python3.11
COPY --from=backend /usr/local/bin/celery /usr/local/bin/celery
COPY ./bin/docker-entrypoint.sh /app/bin/docker-entrypoint.sh
@ -81,7 +81,7 @@ RUN python src/manage.py collectstatic --noinput
# (optional) stage 4
FROM python:3.9-bullseye as development
FROM python:3.11-bookworm as development
RUN apt-get update && apt-get install -y --no-install-recommends \
vim \
@ -96,7 +96,7 @@ RUN mkdir /app/bin
COPY ./requirements /app/requirements
COPY ./bin/docker-entrypoint.sh /app/bin/docker-entrypoint.sh
COPY --from=backend /usr/local/lib/python3.9 /usr/local/lib/python3.9
COPY --from=backend /usr/local/lib/python3.11 /usr/local/lib/python3.11
COPY --from=backend /usr/local/bin/celery /usr/local/bin/celery
COPY --from=backend /app/src/ /app/src/

View file

@ -1,10 +1,8 @@
FROM node:16-bullseye
FROM node:lts-bookworm
WORKDIR /app
RUN mkdir /app/src
COPY package*.json webpack.*.js .babelrc /app/
RUN npm install
COPY ./src /app/src
RUN npm ci --include=dev

View file

@ -1,6 +1,6 @@
static:
stage: build
image: node:16-bullseye
image: node:lts-bookworm
before_script:
- npm install
script:

View file

@ -1,6 +1,6 @@
python-linting:
stage: lint
image: python:3.9-bullseye
image: python:3.11-bookworm
before_script:
- pip install -r requirements/ci.txt
script:
@ -14,7 +14,7 @@ python-linting:
javascript-linting:
stage: lint
image: node:16-bullseye
image: node:lts-bookworm
before_script:
- npm install
script:

View file

@ -4,7 +4,7 @@ python-tests:
services:
- postgres:15
- memcached:1.5.22
image: python:3.9-bullseye
image: python:3.11-bookworm
before_script:
- pip install -r requirements/ci.txt
script:
@ -12,7 +12,7 @@ python-tests:
javascript-tests:
stage: test
image: node:16-bullseye
image: node:lts-bookworm
before_script:
- npm install
script:

27750
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,20 +1,20 @@
{
"name": "newsreader",
"version": "0.4.2",
"version": "0.5.0",
"description": "Application for viewing RSS feeds",
"main": "index.js",
"scripts": {
"lint": "npx prettier \"src/newsreader/js/**/*.js\" --check",
"format": "npx prettier \"src/newsreader/js/**/*.js\" --write",
"build": "npx webpack --config webpack.dev.babel.js",
"build:watch": "npx webpack --config webpack.dev.babel.js --watch",
"build:prod": "npx webpack --config webpack.prod.babel.js",
"test": "npx jest",
"lint": "prettier \"src/newsreader/js/**/*.js\" --check",
"format": "prettier \"src/newsreader/js/**/*.js\" --write",
"build": "webpack --config webpack.dev.babel.js",
"build:watch": "webpack --config webpack.dev.babel.js --watch",
"build:prod": "webpack --config webpack.prod.babel.js",
"test": "jest",
"test:watch": "npm test -- --watch"
},
"repository": {
"type": "git",
"url": "[git@git.fudiggity.nl:5000]:sonny/newsreader.git"
"url": "git@git.fudiggity.nl:sonny/newsreader.git"
},
"author": "Sonny",
"license": "GPL-3.0-or-later",
@ -29,35 +29,33 @@
"redux-thunk": "^2.3.0"
},
"devDependencies": {
"@babel/core": "^7.12.13",
"@babel/plugin-proposal-class-properties": "^7.12.13",
"@babel/plugin-proposal-function-bind": "^7.12.13",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-function-bind": "^7.12.13",
"@babel/plugin-transform-react-jsx": "^7.12.13",
"@babel/plugin-transform-runtime": "^7.12.15",
"@babel/preset-env": "^7.12.13",
"@babel/register": "^7.12.13",
"@babel/runtime": "^7.12.13",
"babel-jest": "^24.9.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.6.0",
"@babel/core": "^7.22.9",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-function-bind": "^7.22.5",
"@babel/plugin-syntax-function-bind": "^7.22.5",
"@babel/plugin-transform-runtime": "^7.22.9",
"@babel/preset-env": "^7.22.9",
"@babel/preset-react": "^7.22.5",
"@babel/register": "^7.22.5",
"@babel/runtime": "^7.22.6",
"babel-jest": "^29.6.2",
"babel-loader": "^9.1.3",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.8.1",
"fetch-mock": "^8.3.2",
"file-loader": "^6.2.0",
"jest": "^24.9.0",
"mini-css-extract-plugin": "^0.9.0",
"jest": "^29.6.2",
"mini-css-extract-plugin": "^2.7.6",
"node-fetch": "^2.6.1",
"prettier": "^1.19.1",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"redux-mock-store": "^1.5.4",
"sass": "^1.52.1",
"sass-loader": "^8.0.2",
"style-loader": "^1.3.0",
"sass": "^1.64.2",
"sass-loader": "^13.3.2",
"style-loader": "^3.3.3",
"url-loader": "^4.1.1",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack-merge": "^4.2.2"
"webpack": "5.88.x",
"webpack-cli": "^5.1.4",
"webpack-merge": "^5.9.0"
}
}

View file

@ -1,32 +1,31 @@
[project]
name = 'newsreader'
version = '0.4.2'
version = '0.5.0'
authors = [{name = 'Sonny', email= 'sonnyba871@gmail.com'}]
license = {text = 'GPL-3.0'}
requires-python = '>=3.11'
dependencies = [
'django~=3.2',
'django~=4.2.0',
'celery~=5.0',
'psycopg2',
'psycopg~=3.1.10',
'django-axes',
'django-axes~=6.0.4',
'django-celery-beat~=2.5.0',
'django-registration-redux~=2.7',
'django-rest-framework',
'drf-yasg',
'django-registration-redux~=2.12.0',
'djangorestframework~=3.14.0',
'python-memcached',
'python-dotenv~=0.12',
'pymemcache~=4.0.0',
'python-dotenv~=1.0.0',
'ftfy~=5.8',
'ftfy~=6.1.1',
'requests',
'requests_oauthlib',
'requests~=2.31.0',
'requests_oauthlib~=1.3.1',
'feedparser',
'bleach',
'beautifulsoup4',
'lxml'
'feedparser~=6.0.10',
'bleach~=6.0.0',
'beautifulsoup4~=4.12.2',
'lxml~=4.9.2'
]
[project.optional-dependencies]
@ -47,4 +46,4 @@ development = [
ci = ['coverage>=5.3.1']
production = ['gunicorn~=20.0', 'sentry-sdk~=1.0']
production = ['gunicorn~=21.2.0', 'sentry-sdk~=1.26.0']

View file

@ -36,13 +36,12 @@ click-repl==0.3.0
# via celery
cron-descriptor==1.4.0
# via django-celery-beat
django==3.2.19
django==4.2.4
# via
# django-axes
# django-celery-beat
# django-timezone-field
# djangorestframework
# drf-yasg
# newsreader (pyproject.toml)
django-axes==6.0.4
# via newsreader (pyproject.toml)
@ -50,35 +49,27 @@ django-celery-beat==2.5.0
# via newsreader (pyproject.toml)
django-registration-redux==2.12
# via newsreader (pyproject.toml)
django-rest-framework==0.1.0
# via newsreader (pyproject.toml)
django-timezone-field==5.1
# via django-celery-beat
djangorestframework==3.14.0
# via
# django-rest-framework
# drf-yasg
drf-yasg==1.21.6
# via newsreader (pyproject.toml)
feedparser==6.0.10
# via newsreader (pyproject.toml)
ftfy==5.9
ftfy==6.1.1
# via newsreader (pyproject.toml)
idna==3.4
# via requests
inflection==0.5.1
# via drf-yasg
kombu==5.3.1
# via celery
lxml==4.9.2
# via newsreader (pyproject.toml)
oauthlib==3.2.2
# via requests-oauthlib
packaging==23.1
# via drf-yasg
prompt-toolkit==3.0.38
# via click-repl
psycopg2==2.9.6
psycopg==3.1.10
# via newsreader (pyproject.toml)
pymemcache==4.0.0
# via newsreader (pyproject.toml)
python-crontab==2.7.1
# via django-celery-beat
@ -86,18 +77,12 @@ python-dateutil==2.8.2
# via
# celery
# python-crontab
python-dotenv==0.21.1
# via newsreader (pyproject.toml)
python-memcached==1.59
python-dotenv==1.0.0
# via newsreader (pyproject.toml)
pytz==2023.3
# via
# django
# django-timezone-field
# djangorestframework
# drf-yasg
pyyaml==6.0
# via drf-yasg
requests==2.31.0
# via
# newsreader (pyproject.toml)
@ -110,7 +95,6 @@ six==1.16.0
# via
# bleach
# python-dateutil
# python-memcached
soupsieve==2.4.1
# via beautifulsoup4
sqlparse==0.4.4
@ -119,12 +103,11 @@ typing-extensions==4.6.3
# via
# asgiref
# kombu
# psycopg
tzdata==2023.3
# via
# celery
# django-celery-beat
uritemplate==4.1.1
# via drf-yasg
urllib3==2.0.3
# via requests
vine==5.0.0

View file

@ -81,14 +81,13 @@ cron-descriptor==1.4.0
# -r requirements/base.txt
# -r requirements/testing.txt
# django-celery-beat
django==3.2.19
django==4.2.4
# via
# -r requirements/base.txt
# django-axes
# django-celery-beat
# django-timezone-field
# djangorestframework
# drf-yasg
# newsreader (pyproject.toml)
django-axes==6.0.4
# via
@ -102,22 +101,12 @@ django-registration-redux==2.12
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
django-rest-framework==0.1.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
django-timezone-field==5.1
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# django-celery-beat
djangorestframework==3.14.0
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# django-rest-framework
# drf-yasg
drf-yasg==1.21.6
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -137,7 +126,7 @@ freezegun==1.2.2
# via
# -r requirements/testing.txt
# newsreader (pyproject.toml)
ftfy==5.9
ftfy==6.1.1
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -146,11 +135,6 @@ idna==3.4
# -r requirements/base.txt
# -r requirements/testing.txt
# requests
inflection==0.5.1
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# drf-yasg
isort==5.12.0
# via
# -r requirements/testing.txt
@ -175,10 +159,8 @@ oauthlib==3.2.2
# requests-oauthlib
packaging==23.1
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# black
# drf-yasg
pathspec==0.11.1
# via
# -r requirements/testing.txt
@ -192,7 +174,7 @@ prompt-toolkit==3.0.38
# -r requirements/base.txt
# -r requirements/testing.txt
# click-repl
psycopg2==2.9.6
psycopg==3.1.10
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -200,6 +182,10 @@ pyflakes==3.0.1
# via
# -r requirements/testing.txt
# autoflake
pymemcache==4.0.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
python-crontab==2.7.1
# via
# -r requirements/base.txt
@ -213,11 +199,7 @@ python-dateutil==2.8.2
# faker
# freezegun
# python-crontab
python-dotenv==0.21.1
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
python-memcached==1.59
python-dotenv==1.0.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -225,15 +207,8 @@ pytz==2023.3
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# django
# django-timezone-field
# djangorestframework
# drf-yasg
pyyaml==6.0
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# drf-yasg
requests==2.31.0
# via
# -r requirements/base.txt
@ -254,7 +229,6 @@ six==1.16.0
# -r requirements/testing.txt
# bleach
# python-dateutil
# python-memcached
soupsieve==2.4.1
# via
# -r requirements/base.txt
@ -281,17 +255,13 @@ typing-extensions==4.6.3
# asgiref
# black
# kombu
# psycopg
tzdata==2023.3
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# celery
# django-celery-beat
uritemplate==4.1.1
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# drf-yasg
urllib3==2.0.3
# via
# -r requirements/base.txt

View file

@ -82,7 +82,7 @@ cron-descriptor==1.4.0
# -r requirements/base.txt
# -r requirements/testing.txt
# django-celery-beat
django==3.2.19
django==4.2.4
# via
# -r requirements/base.txt
# django-axes
@ -91,7 +91,6 @@ django==3.2.19
# django-extensions
# django-timezone-field
# djangorestframework
# drf-yasg
# newsreader (pyproject.toml)
django-axes==6.0.4
# via
@ -109,22 +108,12 @@ django-registration-redux==2.12
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
django-rest-framework==0.1.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
django-timezone-field==5.1
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# django-celery-beat
djangorestframework==3.14.0
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# django-rest-framework
# drf-yasg
drf-yasg==1.21.6
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -144,7 +133,7 @@ freezegun==1.2.2
# via
# -r requirements/testing.txt
# newsreader (pyproject.toml)
ftfy==5.9
ftfy==6.1.1
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -153,11 +142,6 @@ idna==3.4
# -r requirements/base.txt
# -r requirements/testing.txt
# requests
inflection==0.5.1
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# drf-yasg
isort==5.12.0
# via
# -r requirements/testing.txt
@ -182,11 +166,9 @@ oauthlib==3.2.2
# requests-oauthlib
packaging==23.1
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# black
# build
# drf-yasg
pathspec==0.11.1
# via
# -r requirements/testing.txt
@ -202,7 +184,7 @@ prompt-toolkit==3.0.38
# -r requirements/base.txt
# -r requirements/testing.txt
# click-repl
psycopg2==2.9.6
psycopg==3.1.10
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -210,6 +192,10 @@ pyflakes==3.0.1
# via
# -r requirements/testing.txt
# autoflake
pymemcache==4.0.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
pyproject-hooks==1.0.0
# via build
python-crontab==2.7.1
@ -225,11 +211,7 @@ python-dateutil==2.8.2
# faker
# freezegun
# python-crontab
python-dotenv==0.21.1
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
python-memcached==1.59
python-dotenv==1.0.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -237,15 +219,8 @@ pytz==2023.3
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# django
# django-timezone-field
# djangorestframework
# drf-yasg
pyyaml==6.0
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# drf-yasg
requests==2.31.0
# via
# -r requirements/base.txt
@ -266,7 +241,6 @@ six==1.16.0
# -r requirements/testing.txt
# bleach
# python-dateutil
# python-memcached
soupsieve==2.4.1
# via
# -r requirements/base.txt
@ -296,17 +270,13 @@ typing-extensions==4.6.3
# asgiref
# black
# kombu
# psycopg
tzdata==2023.3
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# celery
# django-celery-beat
uritemplate==4.1.1
# via
# -r requirements/base.txt
# -r requirements/testing.txt
# drf-yasg
urllib3==2.0.3
# via
# -r requirements/base.txt

View file

@ -61,14 +61,13 @@ cron-descriptor==1.4.0
# via
# -r requirements/base.txt
# django-celery-beat
django==3.2.19
django==4.2.4
# via
# -r requirements/base.txt
# django-axes
# django-celery-beat
# django-timezone-field
# djangorestframework
# drf-yasg
# newsreader (pyproject.toml)
django-axes==6.0.4
# via
@ -82,20 +81,11 @@ django-registration-redux==2.12
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
django-rest-framework==0.1.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
django-timezone-field==5.1
# via
# -r requirements/base.txt
# django-celery-beat
djangorestframework==3.14.0
# via
# -r requirements/base.txt
# django-rest-framework
# drf-yasg
drf-yasg==1.21.6
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -103,20 +93,16 @@ feedparser==6.0.10
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
ftfy==5.9
ftfy==6.1.1
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
gunicorn==20.1.0
gunicorn==21.2.0
# via newsreader (pyproject.toml)
idna==3.4
# via
# -r requirements/base.txt
# requests
inflection==0.5.1
# via
# -r requirements/base.txt
# drf-yasg
kombu==5.3.1
# via
# -r requirements/base.txt
@ -130,14 +116,16 @@ oauthlib==3.2.2
# -r requirements/base.txt
# requests-oauthlib
packaging==23.1
# via
# -r requirements/base.txt
# drf-yasg
# via gunicorn
prompt-toolkit==3.0.38
# via
# -r requirements/base.txt
# click-repl
psycopg2==2.9.6
psycopg==3.1.10
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
pymemcache==4.0.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -150,25 +138,15 @@ python-dateutil==2.8.2
# -r requirements/base.txt
# celery
# python-crontab
python-dotenv==0.21.1
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
python-memcached==1.59
python-dotenv==1.0.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
pytz==2023.3
# via
# -r requirements/base.txt
# django
# django-timezone-field
# djangorestframework
# drf-yasg
pyyaml==6.0
# via
# -r requirements/base.txt
# drf-yasg
requests==2.31.0
# via
# -r requirements/base.txt
@ -189,7 +167,6 @@ six==1.16.0
# -r requirements/base.txt
# bleach
# python-dateutil
# python-memcached
soupsieve==2.4.1
# via
# -r requirements/base.txt
@ -203,15 +180,12 @@ typing-extensions==4.6.3
# -r requirements/base.txt
# asgiref
# kombu
# psycopg
tzdata==2023.3
# via
# -r requirements/base.txt
# celery
# django-celery-beat
uritemplate==4.1.1
# via
# -r requirements/base.txt
# drf-yasg
urllib3==2.0.3
# via
# -r requirements/base.txt

View file

@ -65,14 +65,13 @@ cron-descriptor==1.4.0
# via
# -r requirements/base.txt
# django-celery-beat
django==3.2.19
django==4.2.4
# via
# -r requirements/base.txt
# django-axes
# django-celery-beat
# django-timezone-field
# djangorestframework
# drf-yasg
# newsreader (pyproject.toml)
django-axes==6.0.4
# via
@ -86,20 +85,11 @@ django-registration-redux==2.12
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
django-rest-framework==0.1.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
django-timezone-field==5.1
# via
# -r requirements/base.txt
# django-celery-beat
djangorestframework==3.14.0
# via
# -r requirements/base.txt
# django-rest-framework
# drf-yasg
drf-yasg==1.21.6
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -113,7 +103,7 @@ feedparser==6.0.10
# newsreader (pyproject.toml)
freezegun==1.2.2
# via newsreader (pyproject.toml)
ftfy==5.9
ftfy==6.1.1
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
@ -121,10 +111,6 @@ idna==3.4
# via
# -r requirements/base.txt
# requests
inflection==0.5.1
# via
# -r requirements/base.txt
# drf-yasg
isort==5.12.0
# via newsreader (pyproject.toml)
kombu==5.3.1
@ -142,10 +128,7 @@ oauthlib==3.2.2
# -r requirements/base.txt
# requests-oauthlib
packaging==23.1
# via
# -r requirements/base.txt
# black
# drf-yasg
# via black
pathspec==0.11.1
# via black
platformdirs==3.8.0
@ -154,12 +137,16 @@ prompt-toolkit==3.0.38
# via
# -r requirements/base.txt
# click-repl
psycopg2==2.9.6
psycopg==3.1.10
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
pyflakes==3.0.1
# via autoflake
pymemcache==4.0.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
python-crontab==2.7.1
# via
# -r requirements/base.txt
@ -171,25 +158,15 @@ python-dateutil==2.8.2
# faker
# freezegun
# python-crontab
python-dotenv==0.21.1
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
python-memcached==1.59
python-dotenv==1.0.0
# via
# -r requirements/base.txt
# newsreader (pyproject.toml)
pytz==2023.3
# via
# -r requirements/base.txt
# django
# django-timezone-field
# djangorestframework
# drf-yasg
pyyaml==6.0
# via
# -r requirements/base.txt
# drf-yasg
requests==2.31.0
# via
# -r requirements/base.txt
@ -208,7 +185,6 @@ six==1.16.0
# -r requirements/base.txt
# bleach
# python-dateutil
# python-memcached
soupsieve==2.4.1
# via
# -r requirements/base.txt
@ -229,15 +205,12 @@ typing-extensions==4.6.3
# asgiref
# black
# kombu
# psycopg
tzdata==2023.3
# via
# -r requirements/base.txt
# celery
# django-celery-beat
uritemplate==4.1.1
# via
# -r requirements/base.txt
# drf-yasg
urllib3==2.0.3
# via
# -r requirements/base.txt

View file

@ -2,7 +2,7 @@ from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.contrib.auth.forms import UserChangeForm
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from newsreader.accounts.models import User

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

View file

@ -19,7 +19,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent.parent.parent
DJANGO_PROJECT_DIR = os.path.join(BASE_DIR, "src", "newsreader")
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: don"t run with debug turned on in production!
DEBUG = False
@ -37,7 +37,6 @@ INSTALLED_APPS = [
"django.forms",
# third party apps
"rest_framework",
"drf_yasg",
"celery",
"django_celery_beat",
"registration",
@ -91,7 +90,7 @@ TEMPLATES = [
WSGI_APPLICATION = "newsreader.wsgi.application"
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
@ -107,17 +106,17 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
"LOCATION": "memcached:11211",
},
"axes": {
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
"LOCATION": "memcached:11211",
},
}
# Logging
# https://docs.djangoproject.com/en/2.2/topics/logging/#configuring-logging
# https://docs.djangoproject.com/en/4.2/topics/logging/#configuring-logging
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
@ -172,7 +171,7 @@ LOGGING = {
}
# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
@ -188,7 +187,7 @@ AUTH_USER_MODEL = "accounts.User"
LOGIN_REDIRECT_URL = "/"
# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "Europe/Amsterdam"
@ -197,12 +196,12 @@ USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "static")
STATICFILES_DIRS = [os.path.join(DJANGO_PROJECT_DIR, "static")]
# https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-STATICFILES_FINDERS
# https://docs.djangoproject.com/en/4.2/ref/settings/#std:setting-STATICFILES_FINDERS
STATICFILES_FINDERS = [
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",

View file

@ -17,17 +17,6 @@ EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
AXES_ENABLED = False
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
"LOCATION": "memcached:11211",
},
"axes": {
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
"LOCATION": "memcached:11211",
},
}
# Project settings
VERSION = get_current_version()
ENVIRONMENT = "gitlab"

View file

@ -11,6 +11,8 @@ SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
ALLOWED_HOSTS = ["127.0.0.1", "localhost", "rss.fudiggity.nl", "django"]
CSRF_TRUSTED_ORIGINS = ["https://rss.fudiggity.nl"]
ADMINS = [
("", email)
for email in os.getenv("ADMINS", "").split(",")

View file

@ -2,12 +2,11 @@ import logging
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import timedelta
from zoneinfo import ZoneInfo
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.utils import timezone
import pytz
from feedparser import parse
from newsreader.news.collection.base import (
@ -58,7 +57,7 @@ class FeedBuilder(PostBuilder):
"published_parsed": "publication_date",
"author": "author",
}
tz = pytz.timezone(self.stream.rule.timezone)
tz = ZoneInfo(self.stream.rule.timezone)
data = {"rule_id": self.stream.rule.pk}
for field, model_field in field_mapping.items():

View file

@ -1,19 +1,30 @@
from datetime import timezone as python_timezone
from zoneinfo import available_timezones
from django import forms
from django.utils.translation import gettext_lazy as _
import pytz
from newsreader.core.forms import CheckboxInput
from newsreader.news.collection.forms.base import CollectionRuleForm
from newsreader.news.collection.models import CollectionRule
def get_timezones():
return [
(
_timezone,
_timezone,
)
for _timezone in available_timezones()
]
class FeedForm(CollectionRuleForm):
timezone = forms.ChoiceField(
widget=forms.Select(attrs={"size": len(pytz.all_timezones)}),
choices=((timezone, timezone) for timezone in pytz.all_timezones),
widget=forms.Select(attrs={"size": len(get_timezones())}),
choices=get_timezones(),
help_text=_("The timezone which the feed uses"),
initial=pytz.utc,
initial=python_timezone.utc,
)
class Meta:

View file

@ -1,10 +1,10 @@
from datetime import timezone
from django import forms
from django.core.exceptions import ValidationError
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
import pytz
from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.forms.base import CollectionRuleForm
from newsreader.news.collection.models import CollectionRule
@ -36,7 +36,7 @@ class SubRedditForm(CollectionRuleForm):
instance = super().save(commit=False)
instance.type = RuleTypeChoices.subreddit
instance.timezone = str(pytz.utc)
instance.timezone = str(timezone.utc)
if commit:
instance.save()

View file

@ -1,8 +1,8 @@
from datetime import timezone
from django import forms
from django.utils.translation import gettext_lazy as _
import pytz
from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.forms.base import CollectionRuleForm
from newsreader.news.collection.models import CollectionRule
@ -21,7 +21,7 @@ class TwitterTimelineForm(CollectionRuleForm):
instance = super().save(commit=False)
instance.type = RuleTypeChoices.twitter_timeline
instance.timezone = str(pytz.utc)
instance.timezone = str(timezone.utc)
instance.url = f"{TWITTER_API_URL}/statuses/user_timeline.json?screen_name={instance.screen_name}&tweet_mode=extended"
if commit:

View file

@ -1,13 +1,24 @@
from datetime import timezone
from zoneinfo import available_timezones
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext as _
import pytz
from newsreader.core.models import TimeStampedModel
from newsreader.news.collection.choices import RuleTypeChoices
def get_timezones():
return [
(
_timezone,
_timezone,
)
for _timezone in available_timezones()
]
class CollectionRuleQuerySet(models.QuerySet):
def enabled(self):
return self.filter(enabled=True)
@ -26,9 +37,9 @@ class CollectionRule(TimeStampedModel):
favicon = models.URLField(blank=True, null=True)
timezone = models.CharField(
choices=((timezone, timezone) for timezone in pytz.all_timezones),
choices=get_timezones(),
max_length=100,
default=str(pytz.utc),
default=str(timezone.utc),
)
category = models.ForeignKey(

View file

@ -2,6 +2,7 @@ import logging
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime, timedelta
from datetime import timezone as _timezone
from html import unescape
from json.decoder import JSONDecodeError
from urllib.parse import urlencode
@ -12,7 +13,6 @@ from django.core.cache import cache
from django.utils import timezone
from django.utils.html import format_html
import pytz
import requests
from newsreader.news.collection.base import (
@ -215,7 +215,8 @@ class RedditBuilder(PostBuilder):
try:
parsed_date = datetime.fromtimestamp(entry_data["created_utc"])
created_date = pytz.utc.localize(parsed_date)
created_date = parsed_date.replace(tzinfo=_timezone.utc)
except (OverflowError, OSError) as e:
raise BuilderParseException(payload=entry) from e
except KeyError as e:

View file

@ -1,7 +1,7 @@
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core.mail import send_mail
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
import requests

View file

@ -1,12 +1,10 @@
import json
from datetime import date, datetime, time
from datetime import date, datetime, time, timezone
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
@ -154,21 +152,21 @@ class NestedRuleListViewTestCase(TestCase):
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
date(2019, 5, 20), time(hour=16, minute=7, second=37), timezone.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
date(2019, 7, 20), time(hour=18, minute=7, second=37), timezone.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
date(2019, 7, 20), time(hour=16, minute=7, second=37), timezone.utc
),
),
]

View file

@ -1,11 +1,10 @@
from datetime import datetime
from datetime import timezone as _timezone
from unittest.mock import Mock
from django.test import TestCase
from django.utils import timezone
import pytz
from freezegun import freeze_time
from newsreader.news.collection.feed import FeedBuilder
@ -35,7 +34,7 @@ class FeedBuilderTestCase(TestCase):
post = posts[0]
publication_date = datetime(
2019, 5, 20, hour=16, minute=32, second=38, tzinfo=pytz.utc
2019, 5, 20, hour=16, minute=32, second=38, tzinfo=_timezone.utc
)
self.assertEqual(
@ -59,7 +58,7 @@ class FeedBuilderTestCase(TestCase):
post = posts[1]
publication_date = datetime(
2019, 5, 20, hour=16, minute=7, second=37, tzinfo=pytz.utc
2019, 5, 20, hour=16, minute=7, second=37, tzinfo=_timezone.utc
)
self.assertEqual(
@ -94,7 +93,7 @@ class FeedBuilderTestCase(TestCase):
post = posts[0]
publication_date = datetime(
2019, 5, 20, hour=16, minute=7, second=37, tzinfo=pytz.utc
2019, 5, 20, hour=16, minute=7, second=37, tzinfo=_timezone.utc
)
self.assertEqual(post.publication_date, publication_date)
@ -109,7 +108,7 @@ class FeedBuilderTestCase(TestCase):
post = posts[1]
publication_date = datetime(
2019, 5, 20, hour=12, minute=19, second=19, tzinfo=pytz.utc
2019, 5, 20, hour=12, minute=19, second=19, tzinfo=_timezone.utc
)
self.assertEqual(post.publication_date, publication_date)

View file

@ -1,12 +1,11 @@
from datetime import date, datetime, time
from datetime import timezone as _timezone
from time import struct_time
from unittest.mock import Mock, patch
from django.test import TestCase
from django.utils import timezone
import pytz
from freezegun import freeze_time
from newsreader.news.collection.exceptions import (
@ -100,7 +99,7 @@ class FeedCollectorTestCase(TestCase):
def test_forbidden(self):
self.mocked_fetch.side_effect = StreamForbiddenException
old_run = pytz.utc.localize(datetime(2019, 10, 30, 12, 30))
old_run = datetime(2019, 10, 30, 12, 30, tzinfo=_timezone.utc)
rule = FeedFactory(last_run=old_run)
collector = FeedCollector()
@ -130,7 +129,7 @@ class FeedCollectorTestCase(TestCase):
self.assertEquals(rule.succeeded, False)
self.assertEquals(rule.error, "Stream timed out")
self.assertEquals(
rule.last_run, pytz.utc.localize(datetime(2019, 10, 30, 12, 30))
rule.last_run, datetime(2019, 10, 30, 12, 30, tzinfo=_timezone.utc)
)
def test_duplicates(self):
@ -139,7 +138,7 @@ class FeedCollectorTestCase(TestCase):
rule = FeedFactory()
aware_datetime = build_publication_date(
struct_time((2019, 5, 20, 16, 7, 37, 0, 140, 0)), pytz.utc
struct_time((2019, 5, 20, 16, 7, 37, 0, 140, 0)), _timezone.utc
)
first_post = FeedPostFactory(
@ -152,7 +151,7 @@ class FeedCollectorTestCase(TestCase):
)
aware_datetime = build_publication_date(
struct_time((2019, 5, 20, 12, 19, 19, 0, 140, 0)), pytz.utc
struct_time((2019, 5, 20, 12, 19, 19, 0, 140, 0)), _timezone.utc
)
second_post = FeedPostFactory(
@ -165,7 +164,7 @@ class FeedCollectorTestCase(TestCase):
)
aware_datetime = build_publication_date(
struct_time((2019, 5, 20, 16, 32, 38, 0, 140, 0)), pytz.utc
struct_time((2019, 5, 20, 16, 32, 38, 0, 140, 0)), _timezone.utc
)
third_post = FeedPostFactory(

View file

@ -1,10 +1,8 @@
from datetime import datetime
from datetime import datetime, timezone
from unittest.mock import Mock
from django.test import TestCase
import pytz
from newsreader.news.collection.reddit import RedditBuilder
from newsreader.news.collection.tests.factories import SubredditFactory
from newsreader.news.collection.tests.reddit.builder.mocks import *
@ -59,7 +57,7 @@ class RedditBuilderTestCase(TestCase):
"https://www.reddit.com/r/linux/comments/hm0qct/linux_experiencesrants_or_educationcertifications/",
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 7, 6, 6, 11, 22))
post.publication_date, datetime(2020, 7, 6, 6, 11, 22, tzinfo=timezone.utc)
)
def test_empty_data(self):

View file

@ -1,12 +1,11 @@
from datetime import datetime
from datetime import timezone as _timezone
from unittest.mock import patch
from uuid import uuid4
from django.test import TestCase
from django.utils import timezone
import pytz
from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.exceptions import (
StreamDeniedException,
@ -82,7 +81,8 @@ class RedditCollectorTestCase(TestCase):
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 7, 11, 22, 23, 24))
post.publication_date,
datetime(2020, 7, 11, 22, 23, 24, tzinfo=_timezone.utc),
)
self.assertEquals(post.author, "HannahB888")
@ -99,7 +99,8 @@ class RedditCollectorTestCase(TestCase):
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 7, 12, 10, 29, 10))
post.publication_date,
datetime(2020, 7, 12, 10, 29, 10, tzinfo=_timezone.utc),
)
self.assertEquals(post.author, "Sebaron")

View file

@ -1,11 +1,9 @@
from datetime import datetime
from datetime import datetime, timezone
from unittest.mock import Mock
from django.test import TestCase
from django.utils.safestring import mark_safe
import pytz
from ftfy import fix_text
from newsreader.news.collection.tests.factories import TwitterTimelineFactory
@ -69,7 +67,7 @@ class TwitterBuilderTestCase(TestCase):
post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1291528756373286914"
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 8, 7, 0, 17, 5))
post.publication_date, datetime(2020, 8, 7, 0, 17, 5, tzinfo=timezone.utc)
)
post = posts["1288550304095416320"]
@ -85,7 +83,7 @@ class TwitterBuilderTestCase(TestCase):
post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1288550304095416320"
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 7, 29, 19, 1, 47))
post.publication_date, datetime(2020, 7, 29, 19, 1, 47, tzinfo=timezone.utc)
)
# note that only one media type can be uploaded to an Tweet
@ -114,7 +112,7 @@ class TwitterBuilderTestCase(TestCase):
post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1269039237166321664"
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 6, 5, 22, 51, 46))
post.publication_date, datetime(2020, 6, 5, 22, 51, 46, tzinfo=timezone.utc)
)
self.assertInHTML(
@ -179,7 +177,7 @@ class TwitterBuilderTestCase(TestCase):
post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1291080532361527296"
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 8, 5, 18, 36, 0))
post.publication_date, datetime(2020, 8, 5, 18, 36, 0, tzinfo=timezone.utc)
)
self.assertIn(full_text, post.body)

View file

@ -1,12 +1,11 @@
from datetime import datetime
from datetime import timezone as _timezone
from unittest.mock import Mock, patch
from uuid import uuid4
from django.test import TestCase
from django.utils import timezone
import pytz
from freezegun import freeze_time
from ftfy import fix_text
@ -67,7 +66,8 @@ class TwitterCollectorTestCase(TestCase):
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 9, 18, 20, 32, 22))
post.publication_date,
datetime(2020, 9, 18, 20, 32, 22, tzinfo=_timezone.utc),
)
title = truncate_text(
@ -89,7 +89,8 @@ class TwitterCollectorTestCase(TestCase):
)
self.assertEquals(
post.publication_date, pytz.utc.localize(datetime(2020, 9, 18, 18, 50, 11))
post.publication_date,
datetime(2020, 9, 18, 18, 50, 11, tzinfo=_timezone.utc),
)
body = fix_text(

View file

@ -1,8 +1,8 @@
from datetime import timezone
from django.test import TestCase
from django.urls import reverse
import pytz
from django_celery_beat.models import PeriodicTask
from newsreader.news.collection.choices import RuleTypeChoices
@ -21,7 +21,7 @@ class FeedCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.form_data.update(
name="new rule",
url="https://www.rss.com/rss",
timezone=pytz.utc,
timezone=str(timezone.utc),
category=str(self.category.pk),
)
@ -34,7 +34,7 @@ class FeedCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.assertEquals(rule.type, RuleTypeChoices.feed)
self.assertEquals(rule.url, "https://www.rss.com/rss")
self.assertEquals(rule.timezone, str(pytz.utc))
self.assertEquals(rule.timezone, str(timezone.utc))
self.assertEquals(rule.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.pk)

View file

@ -1,9 +1,9 @@
from datetime import timezone
from django.test import TestCase
from django.urls import reverse
from django.utils.translation import gettext as _
import pytz
from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.models import CollectionRule
from newsreader.news.collection.reddit import REDDIT_API_URL, REDDIT_URL
@ -38,7 +38,7 @@ class SubRedditCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.assertEquals(rule.type, RuleTypeChoices.subreddit)
self.assertEquals(rule.url, f"{REDDIT_API_URL}/r/aww")
self.assertEquals(rule.timezone, str(pytz.utc))
self.assertEquals(rule.timezone, str(timezone.utc))
self.assertEquals(rule.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.pk)
@ -70,7 +70,7 @@ class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
"name": self.rule.name,
"url": self.rule.url,
"category": str(self.category.pk),
"timezone": pytz.utc,
"timezone": str(timezone.utc),
"reddit_allow_nfsw": False,
"reddit_allow_spoiler": False,
"reddit_allow_viewed": True,
@ -125,7 +125,7 @@ class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.assertEquals(rule.type, RuleTypeChoices.subreddit)
self.assertEquals(rule.url, f"{REDDIT_API_URL}/r/aww")
self.assertEquals(rule.timezone, str(pytz.utc))
self.assertEquals(rule.timezone, str(timezone.utc))
self.assertEquals(rule.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.pk)

View file

@ -1,8 +1,8 @@
from datetime import timezone
from django.test import TestCase
from django.urls import reverse
import pytz
from django_celery_beat.models import PeriodicTask
from newsreader.news.collection.choices import RuleTypeChoices
@ -37,7 +37,7 @@ class TwitterTimelineCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
rule.url,
f"{TWITTER_API_URL}/statuses/user_timeline.json?screen_name=RobertsSpaceInd&tweet_mode=extended",
)
self.assertEquals(rule.timezone, str(pytz.utc))
self.assertEquals(rule.timezone, str(timezone.utc))
self.assertEquals(rule.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.pk)
@ -70,7 +70,7 @@ class TwitterTimelineUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
"name": self.rule.name,
"screen_name": self.rule.screen_name,
"category": str(self.category.pk),
"timezone": pytz.utc,
"timezone": str(timezone.utc),
}
def test_name_change(self):
@ -123,7 +123,7 @@ class TwitterTimelineUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.rule.url,
f"{TWITTER_API_URL}/statuses/user_timeline.json?screen_name=CyberpunkGame&tweet_mode=extended",
)
self.assertEquals(self.rule.timezone, str(pytz.utc))
self.assertEquals(self.rule.timezone, str(timezone.utc))
self.assertEquals(self.rule.favicon, None)
self.assertEquals(self.rule.category.pk, self.category.pk)
self.assertEquals(self.rule.user.pk, self.user.pk)

View file

@ -2,15 +2,14 @@ import logging
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from datetime import timezone as _timezone
from json import JSONDecodeError
from django.conf import settings
from django.core.mail import send_mail
from django.utils import timezone
from django.utils.html import format_html, urlize
from django.utils.translation import ugettext as _
import pytz
from django.utils.translation import gettext as _
from ftfy import fix_text
from requests_oauthlib import OAuth1 as OAuth
@ -82,9 +81,11 @@ class TwitterBuilder(PostBuilder):
Post, "title", self.sanitize_fragment(data["full_text"])
)
publication_date = pytz.utc.localize(
datetime.strptime(data["created_at"], "%a %b %d %H:%M:%S +0000 %Y")
parsed_date = datetime.strptime(
data["created_at"], "%a %b %d %H:%M:%S +0000 %Y"
)
publication_date = parsed_date.replace(tzinfo=_timezone.utc)
except KeyError as e:
raise BuilderMissingDataException(payload=data) from e
except (OverflowError, OSError) as e:

View file

@ -1,10 +1,10 @@
from datetime import datetime
from datetime import timezone as _timezone
from django.conf import settings
from django.db.models.fields import CharField, TextField
from django.utils import timezone
import pytz
import requests
from requests.exceptions import RequestException
@ -22,7 +22,7 @@ def build_publication_date(dt, tz):
except (TypeError, ValueError):
return timezone.now()
return published_parsed.astimezone(pytz.utc)
return published_parsed.astimezone(_timezone.utc)
def fetch(url, auth=None, headers={}):

View file

@ -1,8 +1,8 @@
import json
from django.urls import reverse_lazy
from zoneinfo import available_timezones
import pytz
from django.urls import reverse_lazy
from django_celery_beat.models import IntervalSchedule, PeriodicTask
@ -25,7 +25,9 @@ class CollectionRuleDetailMixin:
context_data = super().get_context_data(**kwargs)
categories = Category.objects.filter(user=self.request.user).order_by("name")
timezones = [timezone for timezone in pytz.all_timezones]
_available_timezones = available_timezones()
timezones = [timezone for timezone in _available_timezones]
context_data["categories"] = categories
context_data["timezones"] = timezones

View file

@ -1,5 +1,5 @@
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _
from rest_framework import filters
from rest_framework.compat import coreapi, coreschema
@ -25,8 +25,8 @@ class ReadFilter(filters.BaseFilterBackend):
required=False,
location="query",
schema=coreschema.String(
title=force_text(self.query_param),
description=force_text(_("Wether posts should be read or not")),
title=force_str(self.query_param),
description=force_str(_("Wether posts should be read or not")),
),
)
]
@ -52,8 +52,8 @@ class SavedFilter(filters.BaseFilterBackend):
required=False,
location="query",
schema=coreschema.String(
title=force_text(self.query_param),
description=force_text(_("Wether posts should be saved or not")),
title=force_str(self.query_param),
description=force_str(_("Wether posts should be saved or not")),
),
)
]

View file

@ -1,12 +1,10 @@
import json
from datetime import datetime
from datetime import datetime, timezone
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
@ -29,15 +27,15 @@ class CategoryListViewTestCase(TestCase):
def test_ordering(self):
categories = [
CategoryFactory(
created=datetime(2019, 5, 20, 16, 7, 37, tzinfo=pytz.utc),
created=datetime(2019, 5, 20, 16, 7, 37, tzinfo=timezone.utc),
user=self.user,
),
CategoryFactory(
created=datetime(2019, 7, 20, 18, 7, 37, tzinfo=pytz.utc),
created=datetime(2019, 7, 20, 18, 7, 37, tzinfo=timezone.utc),
user=self.user,
),
CategoryFactory(
created=datetime(2019, 7, 20, 16, 7, 37, tzinfo=pytz.utc),
created=datetime(2019, 7, 20, 16, 7, 37, tzinfo=timezone.utc),
user=self.user,
),
]
@ -430,12 +428,12 @@ class NestedCategoryPostView(TestCase):
FeedPostFactory.create(
title="Second Reuters post",
rule=reuters_rule,
publication_date=datetime(2019, 5, 21, 15, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 21, 15, tzinfo=timezone.utc),
),
FeedPostFactory.create(
title="First Reuters post",
rule=reuters_rule,
publication_date=datetime(2019, 5, 20, 12, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 20, 12, tzinfo=timezone.utc),
),
]
@ -443,12 +441,12 @@ class NestedCategoryPostView(TestCase):
FeedPostFactory.create(
title="Second Guardian post",
rule=guardian_rule,
publication_date=datetime(2019, 5, 21, 14, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 21, 14, tzinfo=timezone.utc),
),
FeedPostFactory.create(
title="First Guardian post",
rule=guardian_rule,
publication_date=datetime(2019, 5, 20, 11, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 20, 11, tzinfo=timezone.utc),
),
]
@ -456,12 +454,12 @@ class NestedCategoryPostView(TestCase):
FeedPostFactory.create(
title="Second BBC post",
rule=bbc_rule,
publication_date=datetime(2019, 5, 21, 16, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 21, 16, tzinfo=timezone.utc),
),
FeedPostFactory.create(
title="First BBC post",
rule=bbc_rule,
publication_date=datetime(2019, 5, 20, 13, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 20, 13, tzinfo=timezone.utc),
),
]

View file

@ -1,10 +1,8 @@
from datetime import datetime
from datetime import datetime, timezone
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
@ -32,17 +30,17 @@ class PostListViewTestCase(TestCase):
FeedPostFactory(
title="I'm the first post",
rule=rule,
publication_date=datetime(2019, 5, 20, 16, 7, 38, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 20, 16, 7, 38, tzinfo=timezone.utc),
),
FeedPostFactory(
title="I'm the second post",
rule=rule,
publication_date=datetime(2019, 5, 20, 16, 7, 37, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 20, 16, 7, 37, tzinfo=timezone.utc),
),
FeedPostFactory(
title="I'm the third post",
rule=rule,
publication_date=datetime(2019, 5, 20, 16, 7, 36, tzinfo=pytz.utc),
publication_date=datetime(2019, 5, 20, 16, 7, 36, tzinfo=timezone.utc),
),
]

View file

@ -1,6 +1,7 @@
from datetime import timezone
import factory
import factory.fuzzy
import pytz
from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.reddit import REDDIT_API_URL
@ -19,7 +20,7 @@ class PostFactory(factory.django.DjangoModelFactory):
title = factory.Faker("sentence")
body = factory.Faker("paragraph")
author = factory.Faker("name")
publication_date = factory.Faker("date_time_this_year", tzinfo=pytz.utc)
publication_date = factory.Faker("date_time_this_year", tzinfo=timezone.utc)
url = factory.Faker("url")
remote_identifier = factory.Faker("uuid4")

View file

@ -1,5 +1,6 @@
$fa-font-path: '/static/fonts';
$fa-font-path: '~@fortawesome/fontawesome-free/webfonts';
@import '@fortawesome/fontawesome-free/scss/fontawesome';
@import '@fortawesome/fontawesome-free/scss/solid';
@import '@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/brands';
@import '~@fortawesome/fontawesome-free/scss/solid';

View file

@ -6,5 +6,5 @@
{% endblock %}
{% block extrahead %}
<link type="image/png" href="{% static 'favicon.png' %}" rel="shortcut icon" />
<link type="image/png" href="{% static 'images/favicon.png' %}" rel="shortcut icon" />
{% endblock %}

View file

@ -4,7 +4,7 @@
<html>
<head>
<title>Newreader</title>
<link type="image/png" href="{% static 'favicon.png' %}" rel="shortcut icon" />
<link type="image/png" href="{% static 'images/favicon.png' %}" rel="shortcut icon" />
{% block head %}
<link href="{% static 'css/main.css' %}" rel="stylesheet" />
{% endblock %}

View file

@ -3,9 +3,6 @@ from django.contrib import admin
from django.contrib.auth.decorators import login_required
from django.urls import include, path
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from newsreader.accounts.urls import urlpatterns as login_urls
from newsreader.news.core.views import NewsView
from newsreader.news.urls import endpoints as news_endpoints
@ -14,16 +11,12 @@ from newsreader.news.urls import urlpatterns as news_patterns
api_patterns = [path("api/", include((news_endpoints, "news")))]
schema_info = openapi.Info(title="Newsreader API", default_version="v1")
schema_view = get_schema_view(schema_info, patterns=api_patterns)
urlpatterns = [
path("", login_required(NewsView.as_view()), name="index"),
path("", include((news_patterns, "news"))),
path("", include((api_patterns, "api"))),
path("accounts/", include((login_urls, "accounts")), name="accounts"),
path("admin/", admin.site.urls, name="admin"),
path("api/", schema_view.with_ui("swagger"), name="api"),
path("api/auth/", include("rest_framework.urls"), name="rest_framework"),
]

View file

@ -1,6 +1,7 @@
import { resolve } from 'path';
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import CopyPlugin from 'copy-webpack-plugin';
export default {
resolve: { extensions: ['.js', '.scss'] },
@ -10,6 +11,7 @@ export default {
output: {
path: resolve(__dirname, 'src', 'newsreader', 'static'),
filename: 'js/[name].bundle.js',
clean: true,
},
module: {
rules: [
@ -23,26 +25,30 @@ export default {
use: [{ loader: MiniCssExtractPlugin.loader }, 'css-loader', 'sass-loader'],
},
{
test: /\.(ttf|woff|woff2)$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts',
publicPath: '/static/fonts/',
},
test: /\.(ttf|woff|woff2|eot|otf)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[name][ext]',
},
},
{
test: /\.(png|svg|jpg|jpeg)$/,
type: 'asset/resource',
generator: {
filename: 'images/[name][ext]',
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/main.css',
allChunks: true,
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ['js', 'css', 'fonts'],
cleanAfterEveryBuildPatterns: ['!fonts/**'],
new MiniCssExtractPlugin({ filename: 'css/main.css' }),
new CopyPlugin({
patterns: [
{
from: './src/newsreader/assets/images/favicon.png',
to: 'images/',
},
],
}),
],
};