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 # 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 ## 0.4.2
- Set `SECURE_PROXY_SSL_HEADER` setting for production - 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 # 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 \ RUN apt-get update && apt-get install -y --no-install-recommends \
vim \ vim \
@ -18,7 +18,7 @@ RUN pip install -r requirements/base.txt
# stage 2 # 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 \ RUN apt-get update && apt-get install -y --no-install-recommends \
git \ git \
@ -28,15 +28,15 @@ WORKDIR /app
COPY ./*.json ./*.js ./.babelrc /app/ COPY ./*.json ./*.js ./.babelrc /app/
RUN npm ci RUN npm ci --include=dev
COPY ./src /app/src COPY ./src /app/src
RUN npm run build RUN npm run build:prod
# stage 3 # 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 \ RUN apt-get update && apt-get install -y --no-install-recommends \
postgresql-client \ postgresql-client \
@ -51,7 +51,7 @@ RUN mkdir /app/logs
RUN mkdir /app/media RUN mkdir /app/media
RUN mkdir /app/bin 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 --from=backend /usr/local/bin/celery /usr/local/bin/celery
COPY ./bin/docker-entrypoint.sh /app/bin/docker-entrypoint.sh COPY ./bin/docker-entrypoint.sh /app/bin/docker-entrypoint.sh
@ -81,7 +81,7 @@ RUN python src/manage.py collectstatic --noinput
# (optional) stage 4 # (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 \ RUN apt-get update && apt-get install -y --no-install-recommends \
vim \ vim \
@ -96,7 +96,7 @@ RUN mkdir /app/bin
COPY ./requirements /app/requirements COPY ./requirements /app/requirements
COPY ./bin/docker-entrypoint.sh /app/bin/docker-entrypoint.sh 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 /usr/local/bin/celery /usr/local/bin/celery
COPY --from=backend /app/src/ /app/src/ COPY --from=backend /app/src/ /app/src/

View file

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

View file

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

View file

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

View file

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

28042
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,32 +1,31 @@
[project] [project]
name = 'newsreader' name = 'newsreader'
version = '0.4.2' version = '0.5.0'
authors = [{name = 'Sonny', email= 'sonnyba871@gmail.com'}] authors = [{name = 'Sonny', email= 'sonnyba871@gmail.com'}]
license = {text = 'GPL-3.0'} license = {text = 'GPL-3.0'}
requires-python = '>=3.11' requires-python = '>=3.11'
dependencies = [ dependencies = [
'django~=3.2', 'django~=4.2.0',
'celery~=5.0', 'celery~=5.0',
'psycopg2', 'psycopg~=3.1.10',
'django-axes', 'django-axes~=6.0.4',
'django-celery-beat~=2.5.0', 'django-celery-beat~=2.5.0',
'django-registration-redux~=2.7', 'django-registration-redux~=2.12.0',
'django-rest-framework', 'djangorestframework~=3.14.0',
'drf-yasg',
'python-memcached', 'pymemcache~=4.0.0',
'python-dotenv~=0.12', 'python-dotenv~=1.0.0',
'ftfy~=5.8', 'ftfy~=6.1.1',
'requests', 'requests~=2.31.0',
'requests_oauthlib', 'requests_oauthlib~=1.3.1',
'feedparser', 'feedparser~=6.0.10',
'bleach', 'bleach~=6.0.0',
'beautifulsoup4', 'beautifulsoup4~=4.12.2',
'lxml' 'lxml~=4.9.2'
] ]
[project.optional-dependencies] [project.optional-dependencies]
@ -47,4 +46,4 @@ development = [
ci = ['coverage>=5.3.1'] 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 # via celery
cron-descriptor==1.4.0 cron-descriptor==1.4.0
# via django-celery-beat # via django-celery-beat
django==3.2.19 django==4.2.4
# via # via
# django-axes # django-axes
# django-celery-beat # django-celery-beat
# django-timezone-field # django-timezone-field
# djangorestframework # djangorestframework
# drf-yasg
# newsreader (pyproject.toml) # newsreader (pyproject.toml)
django-axes==6.0.4 django-axes==6.0.4
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
@ -50,35 +49,27 @@ django-celery-beat==2.5.0
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
django-registration-redux==2.12 django-registration-redux==2.12
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
django-rest-framework==0.1.0
# via newsreader (pyproject.toml)
django-timezone-field==5.1 django-timezone-field==5.1
# via django-celery-beat # via django-celery-beat
djangorestframework==3.14.0 djangorestframework==3.14.0
# via
# django-rest-framework
# drf-yasg
drf-yasg==1.21.6
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
feedparser==6.0.10 feedparser==6.0.10
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
ftfy==5.9 ftfy==6.1.1
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
idna==3.4 idna==3.4
# via requests # via requests
inflection==0.5.1
# via drf-yasg
kombu==5.3.1 kombu==5.3.1
# via celery # via celery
lxml==4.9.2 lxml==4.9.2
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
oauthlib==3.2.2 oauthlib==3.2.2
# via requests-oauthlib # via requests-oauthlib
packaging==23.1
# via drf-yasg
prompt-toolkit==3.0.38 prompt-toolkit==3.0.38
# via click-repl # via click-repl
psycopg2==2.9.6 psycopg==3.1.10
# via newsreader (pyproject.toml)
pymemcache==4.0.0
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
python-crontab==2.7.1 python-crontab==2.7.1
# via django-celery-beat # via django-celery-beat
@ -86,18 +77,12 @@ python-dateutil==2.8.2
# via # via
# celery # celery
# python-crontab # python-crontab
python-dotenv==0.21.1 python-dotenv==1.0.0
# via newsreader (pyproject.toml)
python-memcached==1.59
# via newsreader (pyproject.toml) # via newsreader (pyproject.toml)
pytz==2023.3 pytz==2023.3
# via # via
# django
# django-timezone-field # django-timezone-field
# djangorestframework # djangorestframework
# drf-yasg
pyyaml==6.0
# via drf-yasg
requests==2.31.0 requests==2.31.0
# via # via
# newsreader (pyproject.toml) # newsreader (pyproject.toml)
@ -110,7 +95,6 @@ six==1.16.0
# via # via
# bleach # bleach
# python-dateutil # python-dateutil
# python-memcached
soupsieve==2.4.1 soupsieve==2.4.1
# via beautifulsoup4 # via beautifulsoup4
sqlparse==0.4.4 sqlparse==0.4.4
@ -119,12 +103,11 @@ typing-extensions==4.6.3
# via # via
# asgiref # asgiref
# kombu # kombu
# psycopg
tzdata==2023.3 tzdata==2023.3
# via # via
# celery # celery
# django-celery-beat # django-celery-beat
uritemplate==4.1.1
# via drf-yasg
urllib3==2.0.3 urllib3==2.0.3
# via requests # via requests
vine==5.0.0 vine==5.0.0

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,17 +17,6 @@ EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
AXES_ENABLED = False 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 # Project settings
VERSION = get_current_version() VERSION = get_current_version()
ENVIRONMENT = "gitlab" 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"] ALLOWED_HOSTS = ["127.0.0.1", "localhost", "rss.fudiggity.nl", "django"]
CSRF_TRUSTED_ORIGINS = ["https://rss.fudiggity.nl"]
ADMINS = [ ADMINS = [
("", email) ("", email)
for email in os.getenv("ADMINS", "").split(",") for email in os.getenv("ADMINS", "").split(",")

View file

@ -2,12 +2,11 @@ import logging
from concurrent.futures import ThreadPoolExecutor, as_completed from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import timedelta from datetime import timedelta
from zoneinfo import ZoneInfo
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.utils import timezone from django.utils import timezone
import pytz
from feedparser import parse from feedparser import parse
from newsreader.news.collection.base import ( from newsreader.news.collection.base import (
@ -58,7 +57,7 @@ class FeedBuilder(PostBuilder):
"published_parsed": "publication_date", "published_parsed": "publication_date",
"author": "author", "author": "author",
} }
tz = pytz.timezone(self.stream.rule.timezone) tz = ZoneInfo(self.stream.rule.timezone)
data = {"rule_id": self.stream.rule.pk} data = {"rule_id": self.stream.rule.pk}
for field, model_field in field_mapping.items(): 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 import forms
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
import pytz
from newsreader.core.forms import CheckboxInput from newsreader.core.forms import CheckboxInput
from newsreader.news.collection.forms.base import CollectionRuleForm from newsreader.news.collection.forms.base import CollectionRuleForm
from newsreader.news.collection.models import CollectionRule from newsreader.news.collection.models import CollectionRule
def get_timezones():
return [
(
_timezone,
_timezone,
)
for _timezone in available_timezones()
]
class FeedForm(CollectionRuleForm): class FeedForm(CollectionRuleForm):
timezone = forms.ChoiceField( timezone = forms.ChoiceField(
widget=forms.Select(attrs={"size": len(pytz.all_timezones)}), widget=forms.Select(attrs={"size": len(get_timezones())}),
choices=((timezone, timezone) for timezone in pytz.all_timezones), choices=get_timezones(),
help_text=_("The timezone which the feed uses"), help_text=_("The timezone which the feed uses"),
initial=pytz.utc, initial=python_timezone.utc,
) )
class Meta: class Meta:

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,12 +1,10 @@
import json import json
from datetime import date, datetime, time from datetime import date, datetime, time, timezone
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
import pytz
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import FeedFactory 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
@ -154,21 +152,21 @@ class NestedRuleListViewTestCase(TestCase):
title="I'm the first post", title="I'm the first post",
rule=rule, rule=rule,
publication_date=datetime.combine( 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( FeedPostFactory(
title="I'm the second post", title="I'm the second post",
rule=rule, rule=rule,
publication_date=datetime.combine( 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( FeedPostFactory(
title="I'm the third post", title="I'm the third post",
rule=rule, rule=rule,
publication_date=datetime.combine( 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 datetime
from datetime import timezone as _timezone
from unittest.mock import Mock from unittest.mock import Mock
from django.test import TestCase from django.test import TestCase
from django.utils import timezone from django.utils import timezone
import pytz
from freezegun import freeze_time from freezegun import freeze_time
from newsreader.news.collection.feed import FeedBuilder from newsreader.news.collection.feed import FeedBuilder
@ -35,7 +34,7 @@ class FeedBuilderTestCase(TestCase):
post = posts[0] post = posts[0]
publication_date = datetime( 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( self.assertEqual(
@ -59,7 +58,7 @@ class FeedBuilderTestCase(TestCase):
post = posts[1] post = posts[1]
publication_date = datetime( 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( self.assertEqual(
@ -94,7 +93,7 @@ class FeedBuilderTestCase(TestCase):
post = posts[0] post = posts[0]
publication_date = datetime( 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) self.assertEqual(post.publication_date, publication_date)
@ -109,7 +108,7 @@ class FeedBuilderTestCase(TestCase):
post = posts[1] post = posts[1]
publication_date = datetime( 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) self.assertEqual(post.publication_date, publication_date)

View file

@ -1,12 +1,11 @@
from datetime import date, datetime, time from datetime import date, datetime, time
from datetime import timezone as _timezone
from time import struct_time from time import struct_time
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from django.test import TestCase from django.test import TestCase
from django.utils import timezone from django.utils import timezone
import pytz
from freezegun import freeze_time from freezegun import freeze_time
from newsreader.news.collection.exceptions import ( from newsreader.news.collection.exceptions import (
@ -100,7 +99,7 @@ class FeedCollectorTestCase(TestCase):
def test_forbidden(self): def test_forbidden(self):
self.mocked_fetch.side_effect = StreamForbiddenException 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) rule = FeedFactory(last_run=old_run)
collector = FeedCollector() collector = FeedCollector()
@ -130,7 +129,7 @@ class FeedCollectorTestCase(TestCase):
self.assertEquals(rule.succeeded, False) self.assertEquals(rule.succeeded, False)
self.assertEquals(rule.error, "Stream timed out") self.assertEquals(rule.error, "Stream timed out")
self.assertEquals( 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): def test_duplicates(self):
@ -139,7 +138,7 @@ class FeedCollectorTestCase(TestCase):
rule = FeedFactory() rule = FeedFactory()
aware_datetime = build_publication_date( 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( first_post = FeedPostFactory(
@ -152,7 +151,7 @@ class FeedCollectorTestCase(TestCase):
) )
aware_datetime = build_publication_date( 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( second_post = FeedPostFactory(
@ -165,7 +164,7 @@ class FeedCollectorTestCase(TestCase):
) )
aware_datetime = build_publication_date( 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( third_post = FeedPostFactory(

View file

@ -1,10 +1,8 @@
from datetime import datetime from datetime import datetime, timezone
from unittest.mock import Mock from unittest.mock import Mock
from django.test import TestCase from django.test import TestCase
import pytz
from newsreader.news.collection.reddit import RedditBuilder from newsreader.news.collection.reddit import RedditBuilder
from newsreader.news.collection.tests.factories import SubredditFactory from newsreader.news.collection.tests.factories import SubredditFactory
from newsreader.news.collection.tests.reddit.builder.mocks import * 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/", "https://www.reddit.com/r/linux/comments/hm0qct/linux_experiencesrants_or_educationcertifications/",
) )
self.assertEquals( 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): def test_empty_data(self):

View file

@ -1,12 +1,11 @@
from datetime import datetime from datetime import datetime
from datetime import timezone as _timezone
from unittest.mock import patch from unittest.mock import patch
from uuid import uuid4 from uuid import uuid4
from django.test import TestCase from django.test import TestCase
from django.utils import timezone from django.utils import timezone
import pytz
from newsreader.news.collection.choices import RuleTypeChoices from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.exceptions import ( from newsreader.news.collection.exceptions import (
StreamDeniedException, StreamDeniedException,
@ -82,7 +81,8 @@ class RedditCollectorTestCase(TestCase):
) )
self.assertEquals( 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") self.assertEquals(post.author, "HannahB888")
@ -99,7 +99,8 @@ class RedditCollectorTestCase(TestCase):
) )
self.assertEquals( 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") 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 unittest.mock import Mock
from django.test import TestCase from django.test import TestCase
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
import pytz
from ftfy import fix_text from ftfy import fix_text
from newsreader.news.collection.tests.factories import TwitterTimelineFactory from newsreader.news.collection.tests.factories import TwitterTimelineFactory
@ -69,7 +67,7 @@ class TwitterBuilderTestCase(TestCase):
post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1291528756373286914" post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1291528756373286914"
) )
self.assertEquals( 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"] post = posts["1288550304095416320"]
@ -85,7 +83,7 @@ class TwitterBuilderTestCase(TestCase):
post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1288550304095416320" post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1288550304095416320"
) )
self.assertEquals( 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 # 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" post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1269039237166321664"
) )
self.assertEquals( 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( self.assertInHTML(
@ -179,7 +177,7 @@ class TwitterBuilderTestCase(TestCase):
post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1291080532361527296" post.url, f"{TWITTER_URL}/RobertsSpaceInd/status/1291080532361527296"
) )
self.assertEquals( 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) self.assertIn(full_text, post.body)

View file

@ -1,12 +1,11 @@
from datetime import datetime from datetime import datetime
from datetime import timezone as _timezone
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from uuid import uuid4 from uuid import uuid4
from django.test import TestCase from django.test import TestCase
from django.utils import timezone from django.utils import timezone
import pytz
from freezegun import freeze_time from freezegun import freeze_time
from ftfy import fix_text from ftfy import fix_text
@ -67,7 +66,8 @@ class TwitterCollectorTestCase(TestCase):
) )
self.assertEquals( 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( title = truncate_text(
@ -89,7 +89,8 @@ class TwitterCollectorTestCase(TestCase):
) )
self.assertEquals( 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( body = fix_text(

View file

@ -1,8 +1,8 @@
from datetime import timezone
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
import pytz
from django_celery_beat.models import PeriodicTask from django_celery_beat.models import PeriodicTask
from newsreader.news.collection.choices import RuleTypeChoices from newsreader.news.collection.choices import RuleTypeChoices
@ -21,7 +21,7 @@ class FeedCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.form_data.update( self.form_data.update(
name="new rule", name="new rule",
url="https://www.rss.com/rss", url="https://www.rss.com/rss",
timezone=pytz.utc, timezone=str(timezone.utc),
category=str(self.category.pk), category=str(self.category.pk),
) )
@ -34,7 +34,7 @@ class FeedCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.assertEquals(rule.type, RuleTypeChoices.feed) self.assertEquals(rule.type, RuleTypeChoices.feed)
self.assertEquals(rule.url, "https://www.rss.com/rss") 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.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk) self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.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.test import TestCase
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
import pytz
from newsreader.news.collection.choices import RuleTypeChoices from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.models import CollectionRule from newsreader.news.collection.models import CollectionRule
from newsreader.news.collection.reddit import REDDIT_API_URL, REDDIT_URL 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.type, RuleTypeChoices.subreddit)
self.assertEquals(rule.url, f"{REDDIT_API_URL}/r/aww") 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.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk) self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.pk) self.assertEquals(rule.user.pk, self.user.pk)
@ -70,7 +70,7 @@ class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
"name": self.rule.name, "name": self.rule.name,
"url": self.rule.url, "url": self.rule.url,
"category": str(self.category.pk), "category": str(self.category.pk),
"timezone": pytz.utc, "timezone": str(timezone.utc),
"reddit_allow_nfsw": False, "reddit_allow_nfsw": False,
"reddit_allow_spoiler": False, "reddit_allow_spoiler": False,
"reddit_allow_viewed": True, "reddit_allow_viewed": True,
@ -125,7 +125,7 @@ class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.assertEquals(rule.type, RuleTypeChoices.subreddit) self.assertEquals(rule.type, RuleTypeChoices.subreddit)
self.assertEquals(rule.url, f"{REDDIT_API_URL}/r/aww") 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.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk) self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.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.test import TestCase
from django.urls import reverse from django.urls import reverse
import pytz
from django_celery_beat.models import PeriodicTask from django_celery_beat.models import PeriodicTask
from newsreader.news.collection.choices import RuleTypeChoices from newsreader.news.collection.choices import RuleTypeChoices
@ -37,7 +37,7 @@ class TwitterTimelineCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
rule.url, rule.url,
f"{TWITTER_API_URL}/statuses/user_timeline.json?screen_name=RobertsSpaceInd&tweet_mode=extended", 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.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk) self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.pk) self.assertEquals(rule.user.pk, self.user.pk)
@ -70,7 +70,7 @@ class TwitterTimelineUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
"name": self.rule.name, "name": self.rule.name,
"screen_name": self.rule.screen_name, "screen_name": self.rule.screen_name,
"category": str(self.category.pk), "category": str(self.category.pk),
"timezone": pytz.utc, "timezone": str(timezone.utc),
} }
def test_name_change(self): def test_name_change(self):
@ -123,7 +123,7 @@ class TwitterTimelineUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.rule.url, self.rule.url,
f"{TWITTER_API_URL}/statuses/user_timeline.json?screen_name=CyberpunkGame&tweet_mode=extended", 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.favicon, None)
self.assertEquals(self.rule.category.pk, self.category.pk) self.assertEquals(self.rule.category.pk, self.category.pk)
self.assertEquals(self.rule.user.pk, self.user.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 concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime from datetime import datetime
from datetime import timezone as _timezone
from json import JSONDecodeError from json import JSONDecodeError
from django.conf import settings from django.conf import settings
from django.core.mail import send_mail from django.core.mail import send_mail
from django.utils import timezone from django.utils import timezone
from django.utils.html import format_html, urlize from django.utils.html import format_html, urlize
from django.utils.translation import ugettext as _ from django.utils.translation import gettext as _
import pytz
from ftfy import fix_text from ftfy import fix_text
from requests_oauthlib import OAuth1 as OAuth from requests_oauthlib import OAuth1 as OAuth
@ -82,9 +81,11 @@ class TwitterBuilder(PostBuilder):
Post, "title", self.sanitize_fragment(data["full_text"]) Post, "title", self.sanitize_fragment(data["full_text"])
) )
publication_date = pytz.utc.localize( parsed_date = datetime.strptime(
datetime.strptime(data["created_at"], "%a %b %d %H:%M:%S +0000 %Y") data["created_at"], "%a %b %d %H:%M:%S +0000 %Y"
) )
publication_date = parsed_date.replace(tzinfo=_timezone.utc)
except KeyError as e: except KeyError as e:
raise BuilderMissingDataException(payload=data) from e raise BuilderMissingDataException(payload=data) from e
except (OverflowError, OSError) as e: except (OverflowError, OSError) as e:

View file

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

View file

@ -1,8 +1,8 @@
import json 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 from django_celery_beat.models import IntervalSchedule, PeriodicTask
@ -25,7 +25,9 @@ class CollectionRuleDetailMixin:
context_data = super().get_context_data(**kwargs) context_data = super().get_context_data(**kwargs)
categories = Category.objects.filter(user=self.request.user).order_by("name") 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["categories"] = categories
context_data["timezones"] = timezones context_data["timezones"] = timezones

View file

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

View file

@ -1,12 +1,10 @@
import json import json
from datetime import datetime from datetime import datetime, timezone
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
import pytz
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import FeedFactory 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
@ -29,15 +27,15 @@ class CategoryListViewTestCase(TestCase):
def test_ordering(self): def test_ordering(self):
categories = [ categories = [
CategoryFactory( 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, user=self.user,
), ),
CategoryFactory( 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, user=self.user,
), ),
CategoryFactory( 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, user=self.user,
), ),
] ]
@ -430,12 +428,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(2019, 5, 21, 15, tzinfo=pytz.utc), publication_date=datetime(2019, 5, 21, 15, tzinfo=timezone.utc),
), ),
FeedPostFactory.create( FeedPostFactory.create(
title="First Reuters post", title="First Reuters post",
rule=reuters_rule, 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( FeedPostFactory.create(
title="Second Guardian post", title="Second Guardian post",
rule=guardian_rule, 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( FeedPostFactory.create(
title="First Guardian post", title="First Guardian post",
rule=guardian_rule, 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( FeedPostFactory.create(
title="Second BBC post", title="Second BBC post",
rule=bbc_rule, 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( FeedPostFactory.create(
title="First BBC post", title="First BBC post",
rule=bbc_rule, 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.test import TestCase
from django.urls import reverse from django.urls import reverse
import pytz
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import FeedFactory 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
@ -32,17 +30,17 @@ class PostListViewTestCase(TestCase):
FeedPostFactory( FeedPostFactory(
title="I'm the first post", title="I'm the first post",
rule=rule, 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( FeedPostFactory(
title="I'm the second post", title="I'm the second post",
rule=rule, 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( FeedPostFactory(
title="I'm the third post", title="I'm the third post",
rule=rule, 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
import factory.fuzzy import factory.fuzzy
import pytz
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.reddit import REDDIT_API_URL from newsreader.news.collection.reddit import REDDIT_API_URL
@ -19,7 +20,7 @@ class PostFactory(factory.django.DjangoModelFactory):
title = factory.Faker("sentence") title = factory.Faker("sentence")
body = factory.Faker("paragraph") body = factory.Faker("paragraph")
author = factory.Faker("name") 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") url = factory.Faker("url")
remote_identifier = factory.Faker("uuid4") 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/fontawesome';
@import '@fortawesome/fontawesome-free/scss/solid'; @import '~@fortawesome/fontawesome-free/scss/regular';
@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 %} {% endblock %}
{% block extrahead %} {% 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 %} {% endblock %}

View file

@ -4,7 +4,7 @@
<html> <html>
<head> <head>
<title>Newreader</title> <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 %} {% block head %}
<link href="{% static 'css/main.css' %}" rel="stylesheet" /> <link href="{% static 'css/main.css' %}" rel="stylesheet" />
{% endblock %} {% endblock %}

View file

@ -3,9 +3,6 @@ from django.contrib import admin
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.urls import include, path 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.accounts.urls import urlpatterns as login_urls
from newsreader.news.core.views import NewsView from newsreader.news.core.views import NewsView
from newsreader.news.urls import endpoints as news_endpoints 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")))] 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 = [ urlpatterns = [
path("", login_required(NewsView.as_view()), name="index"), path("", login_required(NewsView.as_view()), name="index"),
path("", include((news_patterns, "news"))), path("", include((news_patterns, "news"))),
path("", include((api_patterns, "api"))), path("", include((api_patterns, "api"))),
path("accounts/", include((login_urls, "accounts")), name="accounts"), path("accounts/", include((login_urls, "accounts")), name="accounts"),
path("admin/", admin.site.urls, name="admin"), 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"), path("api/auth/", include("rest_framework.urls"), name="rest_framework"),
] ]

View file

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