11 Commits

Author SHA1 Message Date
dependabot[bot]
1ba384baef Merge b7a0ca0fe8 into db23064929 2023-08-28 10:15:07 +00:00
Peter Dwyer
db23064929 library bumps
version bump.
added inital build action
2023-08-28 11:14:53 +01:00
dependabot[bot]
b7a0ca0fe8 Bump django from 4.1.9 to 4.1.10
Bumps [django](https://github.com/django/django) from 4.1.9 to 4.1.10.
- [Commits](https://github.com/django/django/compare/4.1.9...4.1.10)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-06 00:00:47 +00:00
dependabot[bot]
bccbff8b33 Bump sqlparse from 0.4.3 to 0.4.4 (#93)
Bumps [sqlparse](https://github.com/andialbrecht/sqlparse) from 0.4.3 to 0.4.4.
- [Release notes](https://github.com/andialbrecht/sqlparse/releases)
- [Changelog](https://github.com/andialbrecht/sqlparse/blob/master/CHANGELOG)
- [Commits](https://github.com/andialbrecht/sqlparse/compare/0.4.3...0.4.4)

---
updated-dependencies:
- dependency-name: sqlparse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ajurna <ajurna@gmail.com>
2023-05-23 08:50:16 +01:00
dependabot[bot]
05e3db9e42 Bump django from 4.1.7 to 4.1.9 (#94)
Bumps [django](https://github.com/django/django) from 4.1.7 to 4.1.9.
- [Commits](https://github.com/django/django/compare/4.1.7...4.1.9)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ajurna <ajurna@gmail.com>
2023-05-23 08:48:02 +01:00
dependabot[bot]
a47153b917 Bump requests from 2.28.2 to 2.31.0 (#95)
Bumps [requests](https://github.com/psf/requests) from 2.28.2 to 2.31.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.28.2...v2.31.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-23 08:45:45 +01:00
dependabot[bot]
df01235325 Bump webpack from 5.75.0 to 5.76.0 in /frontend (#92)
Bumps [webpack](https://github.com/webpack/webpack) from 5.75.0 to 5.76.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.75.0...v5.76.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 15:54:34 +01:00
Peter Dwyer
7d20447526 library bumps
version bump.
2023-02-16 09:55:32 +00:00
Peter Dwyer
0dfe551b66 library bumps
version bump.
2023-02-16 09:36:50 +00:00
Peter Dwyer
94171ec548 library bumps
version bump.
2023-02-07 14:44:12 +00:00
Peter Dwyer
1fbe359448 library bumps
fix for LoginView.vue reloading instead of logging in.
improved errors for login failing
misc cleanup.
2023-02-07 14:39:26 +00:00
15 changed files with 2538 additions and 2264 deletions

View File

@@ -0,0 +1,19 @@
name: Build and push image
on:
push:
branches: [main]
jobs:
deploy:
runs-on: self-hosted
defaults:
run:
working-directory: /repo
steps:
- name: Checkout repo
run: git pull
- name: Deploy
run: |
docker build . --no-cache -t ajurna/cbwebreader

View File

@@ -6,6 +6,7 @@ Django settings for cbreader project.
import os import os
from datetime import timedelta from datetime import timedelta
from pathlib import Path from pathlib import Path
from typing import Dict, List
import dj_database_url import dj_database_url
from dotenv import load_dotenv from dotenv import load_dotenv
@@ -27,7 +28,7 @@ ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost").split(",")
# Application definition # Application definition
INSTALLED_APPS = ( INSTALLED_APPS = [
"django.contrib.admin", "django.contrib.admin",
"django.contrib.auth", "django.contrib.auth",
"django.contrib.contenttypes", "django.contrib.contenttypes",
@@ -46,7 +47,7 @@ INSTALLED_APPS = (
'django_filters', 'django_filters',
'rest_framework', 'rest_framework',
# 'silk' # 'silk'
) ]
MIDDLEWARE = [ MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
@@ -58,8 +59,7 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware", "django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware",
# 'silk.middleware.SilkyMiddleware', 'csp.middleware.CSPMiddleware',
# 'csp.middleware.CSPMiddleware',
] ]
ROOT_URLCONF = "cbreader.urls" ROOT_URLCONF = "cbreader.urls"
@@ -197,10 +197,10 @@ CSP_FONT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'",) CSP_SCRIPT_SRC = ("'self'",)
CSP_CONNECT_SRC = ("'self'",) CSP_CONNECT_SRC = ("'self'",)
CSP_INCLUDE_NONCE_IN = ['script-src'] CSP_INCLUDE_NONCE_IN = ['script-src']
CSP_SCRIPT_SRC_ATTR = ("'self'",)# "'unsafe-inline'") CSP_SCRIPT_SRC_ATTR = ("'self'",) # "'unsafe-inline'")
PERMISSIONS_POLICY = { PERMISSIONS_POLICY: Dict[str, List] = {
"accelerometer": [], "accelerometer": [],
"ambient-light-sensor": [], "ambient-light-sensor": [],
"autoplay": [], "autoplay": [],

View File

@@ -1,30 +1,11 @@
from .base import * from .base import INSTALLED_APPS, MIDDLEWARE, SILK_ENABLED
INSTALLED_APPS = ( INSTALLED_APPS += ["silk"]
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
'silk',
"snowpenguin.django.recaptcha2",
'bootstrap4',
"comic",
"comic_auth",
)
MIDDLEWARE = [ MIDDLEWARE += [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
'silk.middleware.SilkyMiddleware', 'silk.middleware.SilkyMiddleware',
] ]
SILK_ENABLED = True SILK_ENABLED = True # noqa: F811
SILKY_PYTHON_PROFILER = True SILKY_PYTHON_PROFILER = True

View File

@@ -1,6 +1,6 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.syndication.views import Feed from django.contrib.syndication.views import Feed
from django.db.models import Case, When, PositiveSmallIntegerField, F from django.db.models import Case, When, PositiveSmallIntegerField, F, QuerySet
from django.http import HttpRequest from django.http import HttpRequest
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@@ -18,7 +18,7 @@ class RecentComicsAPI(Feed):
self.user = user_misc.user self.user = user_misc.user
return user_misc.user return user_misc.user
def items(self) -> ComicBook: def items(self) -> QuerySet[ComicBook]:
comics = ComicBook.objects.order_by("-date_added") comics = ComicBook.objects.order_by("-date_added")
comics = comics.annotate( comics = comics.annotate(
classification=Case( classification=Case(

View File

@@ -1,11 +1,11 @@
from typing import Optional, Union from typing import Optional
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import User from django.contrib.auth.base_user import AbstractBaseUser
from django.core.management.base import BaseCommand, CommandParser from django.core.management.base import BaseCommand, CommandParser
from loguru import logger from loguru import logger
from comic.models import ComicBook, Directory from comic.models import Directory
from comic.processing import generate_directory from comic.processing import generate_directory
@@ -27,12 +27,11 @@ class Command(BaseCommand):
self.OUTPUT = options.get('out', False) self.OUTPUT = options.get('out', False)
self.scan_directory() self.scan_directory()
def scan_directory(self, user: Optional[User] = None, directory: Optional[Directory] = None) -> None: def scan_directory(self, user: Optional[AbstractBaseUser] = None, directory: Optional[Directory] = None) -> None:
if not user: if not user:
user_model = get_user_model() user_model = get_user_model()
user = user_model.objects.first() user: AbstractBaseUser = user_model.objects.first()
for item in generate_directory(user, directory): for item in generate_directory(user, directory):
item: Union[Directory, ComicBook] if item is Directory:
if item.type == 'Directory':
logger.info(item) logger.info(item)
self.scan_directory(user, item) self.scan_directory(user, item)

View File

@@ -6,7 +6,7 @@ from typing import NamedTuple, List, Optional, Union
import rarfile import rarfile
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.base_user import AbstractBaseUser
from django.db.models import Count, Q, F, Case, When, PositiveSmallIntegerField, QuerySet, ExpressionWrapper, \ from django.db.models import Count, Q, F, Case, When, PositiveSmallIntegerField, QuerySet, ExpressionWrapper, \
IntegerField IntegerField
@@ -14,7 +14,8 @@ from comic import models
from comic.errors import NotCompatibleArchive from comic.errors import NotCompatibleArchive
def generate_directory(user: User, directory: Optional[models.Directory] = None) -> List[QuerySet]: def generate_directory(user: AbstractBaseUser, directory: Optional[models.Directory] = None) \
-> List[Union[models.Directory, models.ComicBook]]:
dir_path = Path(settings.COMIC_BOOK_VOLUME, directory.path) if directory else settings.COMIC_BOOK_VOLUME dir_path = Path(settings.COMIC_BOOK_VOLUME, directory.path) if directory else settings.COMIC_BOOK_VOLUME
files = [] files = []
@@ -74,7 +75,8 @@ def clean_directories(directories: QuerySet, dir_path: Path, directory: Optional
models.Directory.objects.get(name=stale_directory.name, parent=directory).delete() models.Directory.objects.get(name=stale_directory.name, parent=directory).delete()
def clean_files(files: QuerySet, user: User, dir_path: Path, directory: Optional[models.Directory] = None) -> None: def clean_files(files: QuerySet, user: AbstractBaseUser, dir_path: Path, directory: Optional[models.Directory] = None) \
-> None:
file_list = set(x for x in sorted(dir_path.glob('*')) if x.is_file()) file_list = set(x for x in sorted(dir_path.glob('*')) if x.is_file())
files_db_set = set(Path(dir_path, x.file_name) for x in files) files_db_set = set(Path(dir_path, x.file_name) for x in files)

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@
"vue-toast-notification": "3.0", "vue-toast-notification": "3.0",
"vuejs-paginate-next": "^1.0.2", "vuejs-paginate-next": "^1.0.2",
"vuex": "^4.0.0", "vuex": "^4.0.0",
"webpack": "^5.74.0" "webpack": "^5.76.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.16", "@babel/core": "^7.12.16",

View File

@@ -8,7 +8,7 @@ async function get_access_token() {
let refresh = jwtDecode(store.state.jwt.refresh) let refresh = jwtDecode(store.state.jwt.refresh)
if (access.exp - Date.now()/1000 < 5) { if (access.exp - Date.now()/1000 < 5) {
if (refresh.exp - Date.now()/1000 < 5) { if (refresh.exp - Date.now()/1000 < 5) {
await router.push({name: 'login', params: { username: 'eduardo' }}) await router.push({name: 'login'})
return null return null
} else { } else {
return store.dispatch('refreshToken').then(() => {return store.state.jwt.access}) return store.dispatch('refreshToken').then(() => {return store.state.jwt.access})
@@ -22,9 +22,9 @@ const axios_jwt = axios.create();
axios_jwt.interceptors.request.use(async function (config) { axios_jwt.interceptors.request.use(async function (config) {
let access_token = await get_access_token().catch(() => { let access_token = await get_access_token().catch(() => {
if (router.currentRoute.value.fullPath.includes('login')){ if (router.currentRoute.value.fullPath.includes('login')){
router.push({name: 'login'}) router.push({name: 'login'})
}else { }else {
router.push({name: 'login', query: { next: router.currentRoute.value.fullPath }}) router.push({name: 'login', query: { next: router.currentRoute.value.fullPath }})
} }
}) })
@@ -32,9 +32,9 @@ axios_jwt.interceptors.request.use(async function (config) {
Authorization: "Bearer " + access_token Authorization: "Bearer " + access_token
} }
return config return config
}, function (error) { }, function (error) {
// Do something with request error // Do something with request error
return Promise.reject(error); return Promise.reject(error);
}); });
export default axios_jwt export default axios_jwt

View File

@@ -73,14 +73,22 @@ export default createStore({
if ('next' in router.currentRoute.value.query) { if ('next' in router.currentRoute.value.query) {
router.push(router.currentRoute.value.query.next) router.push(router.currentRoute.value.query.next)
} else { } else {
router.push('/') router.push('browse')
} }
}) })
.catch((error)=>{ .catch((error)=>{
// console.log(error);
const $toast = useToast(); const $toast = useToast();
$toast.error(error.response.data.detail, {position:'top'}); if (error.response.data.detail) {
$toast.error(error.response.data.detail, {position:'top'});
}
if (error.response.data.username) {
$toast.error("Username: " + error.response.data.username, {position:'top'});
}
if (error.response.data.password) {
$toast.error("Password: " + error.response.data.password, {position:'top'});
}
}) })
}, },
refreshToken(){ refreshToken(){

View File

@@ -3,7 +3,7 @@
<div class="row" v-if="!initialSetupRequired"> <div class="row" v-if="!initialSetupRequired">
<div class="col col-lg-4" /> <div class="col col-lg-4" />
<div class="col col-lg-4" id="login-col"> <div class="col col-lg-4" id="login-col">
<form @submit="login"> <form @submit="login" v-on:submit.prevent="onSubmit">
<label class="form-label" for="username">Username</label> <label class="form-label" for="username">Username</label>
<input id="username" placeholder="username" aria-describedby="loginFormControlInputHelpInline" class="form-control" type="text" v-model="username" /> <input id="username" placeholder="username" aria-describedby="loginFormControlInputHelpInline" class="form-control" type="text" v-model="username" />
<div class="form-text" id="loginFormControlInputHelpInline">Please enter your username</div> <div class="form-text" id="loginFormControlInputHelpInline">Please enter your username</div>

0
mypy.ini Normal file
View File

3319
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,52 +3,53 @@ line_length = 119
[tool.poetry] [tool.poetry]
name = "cbwebreader" name = "cbwebreader"
version = "1.1.2" version = "1.1.5"
description = "CBR/Z Web Reader" description = "CBR/Z Web Reader"
authors = ["ajurna <ajurna@gmail.com>"] authors = ["ajurna <ajurna@gmail.com>"]
license = "Creative Commons Attribution-ShareAlike 4.0 International License" license = "Creative Commons Attribution-ShareAlike 4.0 International License"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = "^3.10"
Django = "4.1.2" Django = "^4.1"
gunicorn = "^20.0.4" gunicorn = "^20.0.4"
dj-database-url = "^1.0.0" dj-database-url = "^1.3.0"
python-dotenv = "^0.21.0" python-dotenv = "^1.0.0"
loguru = "^0.6.0" loguru = "^0.7.0"
django-silk = "^5.0.0" django-silk = "^5.0.0"
mysqlclient = "^2.0.1" mysqlclient = "^2.0.1"
psycopg2 = "^2.8.6" psycopg2 = "^2.9.6"
rarfile = "^4.0" rarfile = "^4.0"
django-extensions = "^3.2.1" django-extensions = "^3.2.1"
Pillow = "^9.3.0" Pillow = "^9.3.0"
django-imagekit = "^4.0.2" django-imagekit = "^4.0.2"
PyMuPDF = "~1.20.2" PyMuPDF = "~1.20.2"
django-bootstrap4 = "^22.1" django-bootstrap4 = "^23.1"
django-csp = "^3.7" django-csp = "^3.7"
django-boost = "^2.1" django-boost = "^2.1"
django-sri = "^0.5.0" django-sri = "^0.5.0"
django-permissions-policy = "^4.9.0" django-permissions-policy = "^4.15.0"
djangorestframework = "^3.13.1" djangorestframework = "^3.13.1"
django-filter = "^22.1" django-filter = "^23.1"
django-cors-headers = "^3.13.0" django-cors-headers = "^3.14.0"
djangorestframework-simplejwt = "^5.2.0" djangorestframework-simplejwt = "^5.2.0"
django-webpack-loader = "^1.6.0" django-webpack-loader = "^1.6.0"
drf-yasg = "^1.20.0" drf-yasg = "^1.20.0"
drf-extensions = "^0.7.1" drf-extensions = "^0.7.1"
flake8 = "^5.0.4"
flake8-annotations = "^2.9.1"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
mypy = "^0.971" mypy = "^1.2.0"
Werkzeug = "^2.2" Werkzeug = "^2.2"
pyOpenSSL = "^22.0.0" pyOpenSSL = "^22.0.0"
ipython = "^8.4.0" ipython = "^8.12.0"
coverage = "^6.2" coverage = "^7.2.3"
pre-commit = "^2.20.0" pre-commit = "^3.2.2"
flake8 = "^6.0.0"
flake8-annotations = "^3.0.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pylint = "^2.15.0" pylint = "^2.15.0"
pylint-django = "^2.5.3" pylint-django = "^2.5.3"
mypy = "^1.2.0"
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]

View File

@@ -1,66 +1,60 @@
asgiref==3.5.2 ; python_version >= "3.10" and python_version < "4.0" asgiref==3.6.0 ; python_version >= "3.10" and python_version < "4.0"
attrs==22.1.0 ; python_version >= "3.10" and python_version < "4.0" autopep8==2.0.2 ; python_version >= "3.10" and python_version < "4.0"
autopep8==2.0.0 ; python_version >= "3.10" and python_version < "4.0" beautifulsoup4==4.12.2 ; python_version >= "3.10" and python_version < "4.0"
beautifulsoup4==4.11.1 ; python_version >= "3.10" and python_version < "4.0" certifi==2022.12.7 ; python_version >= "3.10" and python_version < "4"
certifi==2022.9.24 ; python_version >= "3.10" and python_version < "4" charset-normalizer==3.1.0 ; python_version >= "3.10" and python_version < "4"
charset-normalizer==2.1.1 ; python_version >= "3.10" and python_version < "4"
colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32"
coreapi==2.3.3 ; python_version >= "3.10" and python_version < "4.0" coreapi==2.3.3 ; python_version >= "3.10" and python_version < "4.0"
coreschema==0.0.4 ; python_version >= "3.10" and python_version < "4.0" coreschema==0.0.4 ; python_version >= "3.10" and python_version < "4.0"
dj-database-url==1.0.0 ; python_version >= "3.10" and python_version < "4.0" dj-database-url==1.3.0 ; python_version >= "3.10" and python_version < "4.0"
django-appconf==1.0.5 ; python_version >= "3.10" and python_version < "4.0" django-appconf==1.0.5 ; python_version >= "3.10" and python_version < "4.0"
django-boost==2.1 ; python_version >= "3.10" and python_version < "4.0" django-boost==2.1 ; python_version >= "3.10" and python_version < "4.0"
django-bootstrap4==22.2 ; python_version >= "3.10" and python_version < "4.0" django-bootstrap4==23.1 ; python_version >= "3.10" and python_version < "4.0"
django-cors-headers==3.13.0 ; python_version >= "3.10" and python_version < "4.0" django-cors-headers==3.14.0 ; python_version >= "3.10" and python_version < "4.0"
django-csp==3.7 ; python_version >= "3.10" and python_version < "4.0" django-csp==3.7 ; python_version >= "3.10" and python_version < "4.0"
django-extensions==3.2.1 ; python_version >= "3.10" and python_version < "4.0" django-extensions==3.2.1 ; python_version >= "3.10" and python_version < "4.0"
django-filter==22.1 ; python_version >= "3.10" and python_version < "4.0" django-filter==23.1 ; python_version >= "3.10" and python_version < "4.0"
django-imagekit==4.1.0 ; python_version >= "3.10" and python_version < "4.0" django-imagekit==4.1.0 ; python_version >= "3.10" and python_version < "4.0"
django-permissions-policy==4.13.0 ; python_version >= "3.10" and python_version < "4.0" django-permissions-policy==4.15.0 ; python_version >= "3.10" and python_version < "4.0"
django-silk==5.0.2 ; python_version >= "3.10" and python_version < "4.0" django-silk==5.0.3 ; python_version >= "3.10" and python_version < "4.0"
django-sri==0.5.0 ; python_version >= "3.10" and python_version < "4.0" django-sri==0.5.0 ; python_version >= "3.10" and python_version < "4.0"
django-webpack-loader==1.7.0 ; python_version >= "3.10" and python_version < "4.0" django-webpack-loader==1.8.1 ; python_version >= "3.10" and python_version < "4.0"
django==4.1.2 ; python_version >= "3.10" and python_version < "4.0" django==4.2 ; python_version >= "3.10" and python_version < "4.0"
djangorestframework-simplejwt==5.2.2 ; python_version >= "3.10" and python_version < "4.0" djangorestframework-simplejwt==5.2.2 ; python_version >= "3.10" and python_version < "4.0"
djangorestframework==3.14.0 ; python_version >= "3.10" and python_version < "4.0" djangorestframework==3.14.0 ; python_version >= "3.10" and python_version < "4.0"
drf-extensions==0.7.1 ; python_version >= "3.10" and python_version < "4.0" drf-extensions==0.7.1 ; python_version >= "3.10" and python_version < "4.0"
drf-yasg==1.21.4 ; python_version >= "3.10" and python_version < "4.0" drf-yasg==1.21.5 ; python_version >= "3.10" and python_version < "4.0"
flake8-annotations==2.9.1 ; python_version >= "3.10" and python_version < "4.0"
flake8==5.0.4 ; python_version >= "3.10" and python_version < "4.0"
gprof2dot==2022.7.29 ; python_version >= "3.10" and python_version < "4.0" gprof2dot==2022.7.29 ; python_version >= "3.10" and python_version < "4.0"
gunicorn==20.1.0 ; python_version >= "3.10" and python_version < "4.0" gunicorn==20.1.0 ; python_version >= "3.10" and python_version < "4.0"
idna==3.4 ; python_version >= "3.10" and python_version < "4" idna==3.4 ; python_version >= "3.10" and python_version < "4"
inflection==0.5.1 ; python_version >= "3.10" and python_version < "4.0" inflection==0.5.1 ; python_version >= "3.10" and python_version < "4.0"
itypes==1.2.0 ; python_version >= "3.10" and python_version < "4.0" itypes==1.2.0 ; python_version >= "3.10" and python_version < "4.0"
jinja2==3.1.2 ; python_version >= "3.10" and python_version < "4.0" jinja2==3.1.2 ; python_version >= "3.10" and python_version < "4.0"
loguru==0.6.0 ; python_version >= "3.10" and python_version < "4.0" loguru==0.7.0 ; python_version >= "3.10" and python_version < "4.0"
markupsafe==2.1.1 ; python_version >= "3.10" and python_version < "4.0" markupsafe==2.1.2 ; python_version >= "3.10" and python_version < "4.0"
mccabe==0.7.0 ; python_version >= "3.10" and python_version < "4.0"
mysqlclient==2.1.1 ; python_version >= "3.10" and python_version < "4.0" mysqlclient==2.1.1 ; python_version >= "3.10" and python_version < "4.0"
packaging==21.3 ; python_version >= "3.10" and python_version < "4.0" packaging==23.1 ; python_version >= "3.10" and python_version < "4.0"
pilkit==2.0 ; python_version >= "3.10" and python_version < "4.0" pilkit==2.0 ; python_version >= "3.10" and python_version < "4.0"
pillow==9.3.0 ; python_version >= "3.10" and python_version < "4.0" pillow==9.5.0 ; python_version >= "3.10" and python_version < "4.0"
psycopg2==2.9.5 ; python_version >= "3.10" and python_version < "4.0" psycopg2==2.9.6 ; python_version >= "3.10" and python_version < "4.0"
pycodestyle==2.9.1 ; python_version >= "3.10" and python_version < "4.0" pycodestyle==2.10.0 ; python_version >= "3.10" and python_version < "4.0"
pyflakes==2.5.0 ; python_version >= "3.10" and python_version < "4.0"
pyjwt==2.6.0 ; python_version >= "3.10" and python_version < "4.0" pyjwt==2.6.0 ; python_version >= "3.10" and python_version < "4.0"
pymupdf==1.20.2 ; python_version >= "3.10" and python_version < "4.0" pymupdf==1.20.2 ; python_version >= "3.10" and python_version < "4.0"
pyparsing==3.0.9 ; python_version >= "3.10" and python_version < "4.0" python-dotenv==1.0.0 ; python_version >= "3.10" and python_version < "4.0"
python-dateutil==2.8.2 ; python_version >= "3.10" and python_version < "4.0" pytz==2023.3 ; python_version >= "3.10" and python_version < "4.0"
python-dotenv==0.21.0 ; python_version >= "3.10" and python_version < "4.0"
pytz==2022.6 ; python_version >= "3.10" and python_version < "4.0"
rarfile==4.0 ; python_version >= "3.10" and python_version < "4.0" rarfile==4.0 ; python_version >= "3.10" and python_version < "4.0"
requests==2.28.1 ; python_version >= "3.10" and python_version < "4" requests==2.28.2 ; python_version >= "3.10" and python_version < "4"
ruamel-yaml-clib==0.2.7 ; platform_python_implementation == "CPython" and python_version < "3.11" and python_version >= "3.10" ruamel-yaml-clib==0.2.7 ; platform_python_implementation == "CPython" and python_version < "3.11" and python_version >= "3.10"
ruamel-yaml==0.17.21 ; python_version >= "3.10" and python_version < "4.0" ruamel-yaml==0.17.21 ; python_version >= "3.10" and python_version < "4.0"
setuptools==65.5.1 ; python_version >= "3.10" and python_version < "4.0" setuptools==67.6.1 ; python_version >= "3.10" and python_version < "4.0"
six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" six==1.16.0 ; python_version >= "3.10" and python_version < "4.0"
soupsieve==2.3.2.post1 ; python_version >= "3.10" and python_version < "4.0" soupsieve==2.4.1 ; python_version >= "3.10" and python_version < "4.0"
sqlparse==0.4.3 ; python_version >= "3.10" and python_version < "4.0" sqlparse==0.4.3 ; python_version >= "3.10" and python_version < "4.0"
tomli==2.0.1 ; python_version >= "3.10" and python_version < "4.0" tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11"
tzdata==2022.6 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" typing-extensions==4.5.0 ; python_version >= "3.10" and python_version < "4.0"
tzdata==2023.3 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32"
ua-parser==0.16.1 ; python_version >= "3.10" and python_version < "4.0" ua-parser==0.16.1 ; python_version >= "3.10" and python_version < "4.0"
uritemplate==4.1.1 ; python_version >= "3.10" and python_version < "4.0" uritemplate==4.1.1 ; python_version >= "3.10" and python_version < "4.0"
urllib3==1.26.12 ; python_version >= "3.10" and python_version < "4" urllib3==1.26.15 ; python_version >= "3.10" and python_version < "4"
user-agents==2.2.0 ; python_version >= "3.10" and python_version < "4.0" user-agents==2.2.0 ; python_version >= "3.10" and python_version < "4.0"
win32-setctime==1.1.0 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" win32-setctime==1.1.0 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32"