Compare commits
78 Commits
feat/add-i
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
1fdd316d0d
|
|||
|
da5662ceee
|
|||
|
9acb4c8d7c
|
|||
|
36c14ab939
|
|||
|
a9d7aef6dd
|
|||
|
fa942809d9
|
|||
|
29f8475b88
|
|||
|
1875c6fd97
|
|||
|
92aa1fc024
|
|||
|
3551d2b654
|
|||
|
4c21e324f6
|
|||
|
80a80553fe
|
|||
|
15e74660f5
|
|||
|
2b34cadf24
|
|||
|
6dd3355087
|
|||
|
bfdc953e0f
|
|||
|
27567caf78
|
|||
|
97df6349ab
|
|||
|
6d355b603d
|
|||
|
f9f812caf0
|
|||
|
299a600b09
|
|||
|
0cb2794eff
|
|||
|
3d51c6f043
|
|||
|
2a15556513
|
|||
|
ffa0b03661
|
|||
|
3ec8963030
|
|||
|
d70bf79107
|
|||
|
daf0b05bb8
|
|||
|
35d6bb5f2e
|
|||
|
dd936473d8
|
|||
|
787440d56f
|
|||
|
37b0a6a95b
|
|||
|
345914a519
|
|||
|
7e24ded8ee
|
|||
|
64edf6656e
|
|||
|
a2ad8e7ac9
|
|||
|
a0b4697c61
|
|||
|
983384f62b
|
|||
|
668ddccea5
|
|||
|
6dd826c3bd
|
|||
|
e74c1fb28d
|
|||
|
cb19bc6262
|
|||
|
a918ee73c4
|
|||
|
5913e847bc
|
|||
|
18b21b0892
|
|||
|
efb3799e12
|
|||
|
306d39bd22
|
|||
|
e503d69235
|
|||
|
57ec3162d0
|
|||
|
c4e9ec5484
|
|||
|
c8732a05cb
|
|||
|
6810e540e5
|
|||
|
21500e0f10
|
|||
|
be42d71bb8
|
|||
|
b5e9e1ec66
|
|||
|
d575c836e9
|
|||
|
84a6c4cf5e
|
|||
|
e46f034d9e
|
|||
|
dc7e34f5b6
|
|||
|
f002651e2a
|
|||
|
c789eeb4ff
|
|||
|
acb6ea58ce
|
|||
|
72fca4228c
|
|||
|
9f779407af
|
|||
|
f2f594afb6
|
|||
|
95ab896e5f
|
|||
|
4f58cb0320
|
|||
|
294ea9a28b
|
|||
|
e56aff1a5c
|
|||
|
71d4580a82
|
|||
|
0356374870
|
|||
|
ffc33d3be4
|
|||
|
730e041794
|
|||
|
e0f3f094ff
|
|||
|
157ee875e1
|
|||
|
12de01c2dc
|
|||
|
718aeb9cf5
|
|||
|
9761daf820
|
@@ -1,7 +1,7 @@
|
||||
# Django project
|
||||
/media/
|
||||
/static/
|
||||
*.sqlite3
|
||||
# *.sqlite3
|
||||
|
||||
# Python and others
|
||||
__pycache__
|
||||
@@ -37,3 +37,6 @@ wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
.venv/
|
||||
|
||||
gitea/
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -55,3 +55,6 @@ docs/ref/modules/
|
||||
|
||||
# Media (managed by wagtail)
|
||||
media/
|
||||
|
||||
# Gitea data
|
||||
gitea/data/
|
||||
|
||||
91
Dockerfile
91
Dockerfile
@@ -1,60 +1,57 @@
|
||||
# Use an official Python runtime based on Debian 12 "bookworm" as a parent image.
|
||||
FROM python:3.12-slim-bookworm
|
||||
FROM python:3.14-slim-bookworm AS builder
|
||||
|
||||
# Add user that will be used in the container.
|
||||
RUN useradd wagtail
|
||||
RUN useradd -m kursy
|
||||
|
||||
# Port used by this container to serve HTTP.
|
||||
EXPOSE 8000
|
||||
ENV NODE_VERSION=24.14.1
|
||||
|
||||
# Set environment variables.
|
||||
# 1. Force Python stdout and stderr streams to be unbuffered.
|
||||
# 2. Set PORT variable that is used by Gunicorn. This should match "EXPOSE"
|
||||
# command.
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PORT=8000
|
||||
# install uv
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||
|
||||
# Install system packages required by Wagtail and Django.
|
||||
RUN apt-get update --yes --quiet && apt-get install --yes --quiet --no-install-recommends \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
libmariadb-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
zlib1g-dev \
|
||||
libwebp-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# install nodejs
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
|
||||
apt-get install -y nodejs
|
||||
|
||||
# Install the application server.
|
||||
RUN pip install "gunicorn==20.0.4"
|
||||
# copy project files
|
||||
WORKDIR /app
|
||||
COPY pyproject.toml uv.lock ./
|
||||
|
||||
# Install the project requirements.
|
||||
COPY requirements.txt /
|
||||
RUN pip install -r /requirements.txt
|
||||
RUN chown kursy:kursy /app -R
|
||||
|
||||
# Use /app folder as a directory where the source code is stored.
|
||||
USER kursy
|
||||
|
||||
# install project dependencies
|
||||
RUN uv sync
|
||||
|
||||
COPY --chown=kursy:kursy . .
|
||||
|
||||
# install tailwind
|
||||
WORKDIR /app/theme/static_src
|
||||
RUN npm install
|
||||
|
||||
# collect static files
|
||||
WORKDIR /app
|
||||
RUN uv run python manage.py collectstatic --noinput --clear
|
||||
|
||||
|
||||
# --- RUNTIME IMAGE ---
|
||||
FROM python:3.14-slim-bookworm
|
||||
|
||||
RUN useradd -m kursy
|
||||
WORKDIR /app
|
||||
|
||||
# Set this directory to be owned by the "wagtail" user. This Wagtail project
|
||||
# uses SQLite, the folder needs to be owned by the user that
|
||||
# will be writing to the database file.
|
||||
RUN chown wagtail:wagtail /app
|
||||
RUN mkdir -p /app/data && chown kursy:kursy /app/data
|
||||
|
||||
# Copy the source code of the project into the container.
|
||||
COPY --chown=wagtail:wagtail . .
|
||||
USER kursy
|
||||
|
||||
# Use user "wagtail" to run the build commands below and the server itself.
|
||||
USER wagtail
|
||||
COPY --from=builder --chown=kursy:kursy /app/.venv /app/.venv
|
||||
COPY --from=builder --chown=kursy:kursy /app /app
|
||||
|
||||
# Collect static files.
|
||||
RUN python manage.py collectstatic --noinput --clear
|
||||
ENV PATH="/app/.venv/bin:$PATH" \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PORT=8000
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD set -xe; python manage.py migrate --noinput; python manage.py runserver 0.0.0.0:8000
|
||||
|
||||
# Runtime command that executes when "docker run" is called, it does the
|
||||
# following:
|
||||
# 1. Migrate the database.
|
||||
# 2. Start the application server.
|
||||
# WARNING:
|
||||
# Migrating database at the same time as starting the server IS NOT THE BEST
|
||||
# PRACTICE. The database should be migrated manually or using the release
|
||||
# phase facilities of your hosting platform. This is used only so the
|
||||
# Wagtail instance can be started with a simple "docker run" command.
|
||||
CMD set -xe; python manage.py migrate --noinput; gunicorn kursy.wsgi:application
|
||||
|
||||
89
README.md
Normal file
89
README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Studio77 (kursy)
|
||||
|
||||
## Instalacja
|
||||
|
||||
### Wymagania
|
||||
|
||||
- `uv` >= 0.11.0
|
||||
- `python` >= 3.14 (instalowany automatycznie przez `uv`)
|
||||
- `node` >= 24.14.1 (LTS)
|
||||
- `npm` >= 9.2.0 (LTS)
|
||||
|
||||
### Instalacja wymaganych narzędzi
|
||||
|
||||
1. `uv` - można zainstalować za pomocą skryptu instalacyjnego dostępnego na [stronie projektu](https://docs.astral.sh/uv/getting-started/installation):
|
||||
|
||||
```bash
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
2. `node` i `npm` - można zainstalować za pomocą [Node Version Manager (nvm)](https://nodejs.org/en/download):
|
||||
|
||||
```bash
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
|
||||
|
||||
\. "$HOME/.nvm/nvm.sh"
|
||||
|
||||
nvm install 24
|
||||
```
|
||||
|
||||
### Instalacja projektu
|
||||
|
||||
1. Sklonuj repozytorium:
|
||||
|
||||
```bash
|
||||
git clone http://192.168.190:3000/StudioCodeLab/kursy.git
|
||||
cd kursy
|
||||
```
|
||||
|
||||
2. Zainstaluj zależności:
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
```
|
||||
|
||||
3. Zainstaluj zależności tailwind:
|
||||
|
||||
```bash
|
||||
cd theme/static_src
|
||||
npm install
|
||||
cd ../..
|
||||
```
|
||||
|
||||
## Pierwsze uruchomienie
|
||||
|
||||
1. Wykonaj migracje bazy danych:
|
||||
|
||||
```bash
|
||||
uv run python manage.py migrate
|
||||
```
|
||||
|
||||
2. Utwórz superużytkownika (admina):
|
||||
|
||||
```bash
|
||||
uv run python manage.py createsuperuser
|
||||
```
|
||||
|
||||
## Użycie
|
||||
|
||||
### Uruchom serwery
|
||||
|
||||
- Django:
|
||||
|
||||
```bash
|
||||
uv run python manage.py runserver
|
||||
```
|
||||
|
||||
- Tailwind:
|
||||
|
||||
```bash
|
||||
cd theme/static_src
|
||||
npm run dev
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Oba serwery muszą być uruchomione równolegle, aby aplikacja działała poprawnie.
|
||||
|
||||
## Autorzy
|
||||
|
||||
- [Artur Borecki](https://github.com/pufereq)
|
||||
38
docker-compose.yml
Normal file
38
docker-compose.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
networks:
|
||||
gitea:
|
||||
external: false
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: docker.gitea.com/gitea:latest
|
||||
container_name: gitea
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=sqlite3
|
||||
- GITEA__server__ROOT_URL=http://localhost:3000/
|
||||
restart: always
|
||||
network_mode: host
|
||||
# networks:
|
||||
# - gitea
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- ./gitea/data:/data
|
||||
# - ./gitea/config:/data/gitea/conf
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "3022:3022"
|
||||
|
||||
# kursy:
|
||||
# build: .
|
||||
# container_name: kursy
|
||||
# restart: unless-stopped
|
||||
# networks:
|
||||
# - gitea
|
||||
# volumes:
|
||||
# - ./db:/app/db
|
||||
# ports:
|
||||
# - "8000:8000"
|
||||
820
gitea/config/app.ini
Normal file
820
gitea/config/app.ini
Normal file
@@ -0,0 +1,820 @@
|
||||
; ; Copy required sections to your own app.ini (default is custom/conf/app.ini)
|
||||
; ; and modify as needed.
|
||||
; ; Do not copy the whole file as-is, as it contains some invalid sections for illustrative purposes.
|
||||
; ; If you don't know what a setting is you should not set it.
|
||||
; ;
|
||||
; ; see https://docs.gitea.com/administration/config-cheat-sheet for additional documentation.
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ; Default Configuration (non-`app.ini` configuration)
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; These values are environment-dependent but form the basis of a lot of values. They will be
|
||||
; ; reported as part of the default configuration when running `gitea help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up.
|
||||
; ;
|
||||
; ; - _`AppPath`_: This is the absolute path of the running gitea binary.
|
||||
; ; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy:
|
||||
; ; - The "WORK_PATH" option in "app.ini" file
|
||||
; ; - The `--work-path` flag passed to the binary
|
||||
; ; - The environment variable `$GITEA_WORK_DIR`
|
||||
; ; - A built-in value set at build time (see building from source)
|
||||
; ; - Otherwise it defaults to the directory of the _`AppPath`_
|
||||
; ; - If any of the above are relative paths then they are made absolute against the directory of the _`AppPath`_
|
||||
; ; - _`CustomPath`_: This is the base directory for custom templates and other options. It is determined by using the first set thing in the following hierarchy:
|
||||
; ; - The `--custom-path` flag passed to the binary
|
||||
; ; - The environment variable `$GITEA_CUSTOM`
|
||||
; ; - A built-in value set at build time (see building from source)
|
||||
; ; - Otherwise it defaults to _`AppWorkPath`_`/custom`
|
||||
; ; - If any of the above are relative paths then they are made absolute against the directory of the _`AppWorkPath`_
|
||||
; ; - _`CustomConf`_: This is the path to the `app.ini` file.
|
||||
; ; - The `--config` flag passed to the binary
|
||||
; ; - A built-in value set at build time (see building from source)
|
||||
; ; - Otherwise it defaults to _`CustomPath`_`/conf/app.ini`
|
||||
; ; - If any of the above are relative paths then they are made absolute against the directory of the _`CustomPath`_
|
||||
; ;
|
||||
; ; In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ; General Settings
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; App name that shows in every page title
|
||||
; Gitea: Git with a cup of tea
|
||||
APP_NAME = Studio77 Gitea (test instance)
|
||||
; ;
|
||||
; ; RUN_USER will automatically detect the current user - but you can set it here change it if you run locally
|
||||
; git
|
||||
RUN_USER = gitea
|
||||
WORK_PATH = /var/lib/gitea
|
||||
RUN_MODE = prod
|
||||
|
||||
; ;
|
||||
; ; Application run mode, affects performance and debugging: "dev" or "prod", default is "prod"
|
||||
; ; Mode "dev" makes Gitea easier to develop and debug, values other than "dev" are treated as "prod" which is for production use.
|
||||
; RUN_MODE = prod
|
||||
; ;
|
||||
; ; The working directory, see the comment of AppWorkPath above
|
||||
; WORK_PATH =
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[server]
|
||||
SSH_DOMAIN = 127.0.0.1
|
||||
DOMAIN = 127.0.0.1
|
||||
HTTP_PORT = 3000
|
||||
ROOT_URL = http://localhost:3000/
|
||||
APP_DATA_PATH = /var/lib/gitea/data
|
||||
DISABLE_SSH = false
|
||||
SSH_PORT = 22
|
||||
LFS_START_SERVER = true
|
||||
LFS_JWT_SECRET = ZlMvLXiVZtuaVymLGuO4Qg5dFHCQ45fIzui99Qw9ecM
|
||||
OFFLINE_MODE = true
|
||||
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; The protocol the server listens on. One of "http", "https", "http+unix", "fcgi" or "fcgi+unix".
|
||||
; PROTOCOL = http
|
||||
; ;
|
||||
; ; Set the domain for the server.
|
||||
; DOMAIN = localhost
|
||||
; ;
|
||||
; ; The AppURL is used to generate public URL links, defaults to "{PROTOCOL}://{DOMAIN}:{HTTP_PORT}/".
|
||||
; ; Most users should set it to the real website URL of their Gitea instance when there is a reverse proxy.
|
||||
; ROOT_URL =
|
||||
; ;
|
||||
; ; Controls how to detect the public URL.
|
||||
; ; Although it defaults to "legacy" (to avoid breaking existing users), most instances should use the "auto" behavior,
|
||||
; ; especially when the Gitea instance needs to be accessed in a container network.
|
||||
; ; * legacy: detect the public URL from "Host" header if "X-Forwarded-Proto" header exists, otherwise use "ROOT_URL".
|
||||
; ; * auto: always use "Host" header, and also use "X-Forwarded-Proto" header if it exists. If no "Host" header, use "ROOT_URL".
|
||||
; PUBLIC_URL_DETECTION = legacy
|
||||
; ;
|
||||
; ; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.
|
||||
; ; DO NOT USE IT IN PRODUCTION!!!
|
||||
; USE_SUB_URL_PATH = false
|
||||
; ;
|
||||
; ; when STATIC_URL_PREFIX is empty it will follow ROOT_URL
|
||||
; STATIC_URL_PREFIX =
|
||||
; ;
|
||||
; ; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
|
||||
; ; If PROTOCOL is set to "http+unix" or "fcgi+unix", this should be the name of the Unix socket file to use.
|
||||
; ; Relative paths will be made absolute against the _`AppWorkPath`_.
|
||||
; HTTP_ADDR = 0.0.0.0
|
||||
; ;
|
||||
; ; The port to listen on for "http" or "https" protocol. Leave empty when using a unix socket.
|
||||
; HTTP_PORT = 3000
|
||||
; ;
|
||||
; ; Expect PROXY protocol headers on connections
|
||||
; USE_PROXY_PROTOCOL = false
|
||||
; ;
|
||||
; ; Use PROXY protocol in TLS Bridging mode
|
||||
; PROXY_PROTOCOL_TLS_BRIDGING = false
|
||||
; ;
|
||||
; ; Timeout to wait for PROXY protocol header (set to 0 to have no timeout)
|
||||
; PROXY_PROTOCOL_HEADER_TIMEOUT = 5s
|
||||
; ;
|
||||
; ; Accept PROXY protocol headers with UNKNOWN type
|
||||
; PROXY_PROTOCOL_ACCEPT_UNKNOWN = false
|
||||
; ;
|
||||
; ; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server
|
||||
; ; will be started on PORT_TO_REDIRECT and it will redirect plain, non-secure http requests to the main
|
||||
; ; ROOT_URL. Defaults are false for REDIRECT_OTHER_PORT and 80 for
|
||||
; ; PORT_TO_REDIRECT.
|
||||
; REDIRECT_OTHER_PORT = false
|
||||
; PORT_TO_REDIRECT = 80
|
||||
; ;
|
||||
; ; expect PROXY protocol header on connections to https redirector, defaults to USE_PROXY_PROTOCOL
|
||||
; REDIRECTOR_USE_PROXY_PROTOCOL =
|
||||
; ; Minimum and maximum supported TLS versions
|
||||
; SSL_MIN_VERSION=TLSv1.2
|
||||
; SSL_MAX_VERSION=
|
||||
; ;
|
||||
; ; SSL Curve Preferences
|
||||
; SSL_CURVE_PREFERENCES=X25519,P256
|
||||
; ;
|
||||
; ; SSL Cipher Suites
|
||||
; SSL_CIPHER_SUITES=; Will default to "ecdhe_ecdsa_with_aes_256_gcm_sha384,ecdhe_rsa_with_aes_256_gcm_sha384,ecdhe_ecdsa_with_aes_128_gcm_sha256,ecdhe_rsa_with_aes_128_gcm_sha256,ecdhe_ecdsa_with_chacha20_poly1305,ecdhe_rsa_with_chacha20_poly1305" if aes is supported by hardware, otherwise chacha will be first.
|
||||
; ;
|
||||
; ; Timeout for any write to the connection. (Set to -1 to disable all timeouts.)
|
||||
; PER_WRITE_TIMEOUT = 30s
|
||||
; ;
|
||||
; ; Timeout per Kb written to connections.
|
||||
; PER_WRITE_PER_KB_TIMEOUT = 30s
|
||||
; ;
|
||||
; ; Permission for unix socket
|
||||
; UNIX_SOCKET_PERMISSION = 666
|
||||
; ;
|
||||
; ; Local (DMZ) URL for Gitea workers (such as SSH update) accessing web service. In
|
||||
; ; most cases you do not need to change the default value. Alter it only if
|
||||
; ; your SSH server node is not the same as HTTP node. For different protocol, the default
|
||||
; ; values are different. If `PROTOCOL` is `http+unix`, the default value is `http://unix/`.
|
||||
; ; If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `{PROTOCOL}://{HTTP_ADDR}:{HTTP_PORT}/`.
|
||||
; ; If listen on `0.0.0.0`, the default value is `{PROTOCOL}://localhost:{HTTP_PORT}/`.
|
||||
; ; Otherwise the default value is `{PROTOCOL}://{HTTP_ADDR}:{HTTP_PORT}/`.
|
||||
; ; Most users don't need (and shouldn't) set this value.
|
||||
; LOCAL_ROOT_URL =
|
||||
; ;
|
||||
; ; When making local connections pass the PROXY protocol header, defaults to USE_PROXY_PROTOCOL
|
||||
; LOCAL_USE_PROXY_PROTOCOL =
|
||||
; ;
|
||||
; ; Disable SSH feature when not available
|
||||
; DISABLE_SSH = false
|
||||
; ;
|
||||
; ; Whether to use the builtin SSH server or not.
|
||||
; START_SSH_SERVER = false
|
||||
; ;
|
||||
; ; Expect PROXY protocol header on connections to the built-in SSH server
|
||||
; SSH_SERVER_USE_PROXY_PROTOCOL = false
|
||||
; ;
|
||||
; ; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER.
|
||||
; BUILTIN_SSH_SERVER_USER =
|
||||
; ;
|
||||
; ; Domain name to be exposed in clone URL, defaults to DOMAIN or the domain part of ROOT_URL
|
||||
; SSH_DOMAIN =
|
||||
; ;
|
||||
; ; SSH username displayed in clone URLs. It defaults to BUILTIN_SSH_SERVER_USER or RUN_USER.
|
||||
; ; If it is set to "(DOER_USERNAME)", it will use current signed-in user's username.
|
||||
; ; This option is only for some advanced users who have configured their SSH reverse-proxy
|
||||
; ; and need to use different usernames for git SSH clone.
|
||||
; ; Most users should just leave it blank.
|
||||
; SSH_USER =
|
||||
; ;
|
||||
; ; The network interface the builtin SSH server should listen on
|
||||
; SSH_LISTEN_HOST =
|
||||
; ;
|
||||
; ; Port number to be exposed in clone URL
|
||||
; SSH_PORT = 22
|
||||
; ;
|
||||
; ; The port number the builtin SSH server should listen on, defaults to SSH_PORT
|
||||
; SSH_LISTEN_PORT =
|
||||
; ;
|
||||
; ; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
|
||||
; SSH_ROOT_PATH =
|
||||
; ;
|
||||
; ; Gitea will create a authorized_keys file by default when it is not using the internal ssh server
|
||||
; ; If you intend to use the AuthorizedKeysCommand functionality then you should turn this off.
|
||||
; SSH_CREATE_AUTHORIZED_KEYS_FILE = true
|
||||
; ;
|
||||
; ; Gitea will create a authorized_principals file by default when it is not using the internal ssh server
|
||||
; ; If you intend to use the AuthorizedPrincipalsCommand functionality then you should turn this off.
|
||||
; SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE = true
|
||||
; ;
|
||||
; ; For the builtin SSH server, choose the supported ciphers/key-exchange-algorithms/MACs for SSH connections.
|
||||
; ; The supported names are listed in https://github.com/golang/crypto/blob/master/ssh/common.go.
|
||||
; ; Leave them empty to use the Golang crypto's recommended default values.
|
||||
; ; For system SSH (non-builtin SSH server), this setting has no effect.
|
||||
; SSH_SERVER_CIPHERS =
|
||||
; SSH_SERVER_KEY_EXCHANGES =
|
||||
; SSH_SERVER_MACS =
|
||||
; ;
|
||||
; ; For the built-in SSH server, choose the keypair to offer as the host key
|
||||
; ; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub
|
||||
; ; relative paths are made absolute relative to the APP_DATA_PATH
|
||||
; SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
|
||||
; ;
|
||||
; ; Enable SSH Authorized Key Backup when rewriting all keys, default is false
|
||||
; SSH_AUTHORIZED_KEYS_BACKUP = false
|
||||
; ;
|
||||
; ; Determines which principals to allow
|
||||
; ; - empty: if SSH_TRUSTED_USER_CA_KEYS is empty this will default to off, otherwise will default to email, username.
|
||||
; ; - off: Do not allow authorized principals
|
||||
; ; - email: the principal must match the user's email
|
||||
; ; - username: the principal must match the user's username
|
||||
; ; - anything: there will be no checking on the content of the principal
|
||||
; SSH_AUTHORIZED_PRINCIPALS_ALLOW = email, username
|
||||
; ;
|
||||
; ; Enable SSH Authorized Principals Backup when rewriting all keys, default is true
|
||||
; SSH_AUTHORIZED_PRINCIPALS_BACKUP = true
|
||||
; ;
|
||||
; ; Specifies the public keys of certificate authorities that are trusted to sign user certificates for authentication.
|
||||
; ; Multiple keys should be comma separated.
|
||||
; ; E.g."ssh-<algorithm> <key>". or "ssh-<algorithm> <key1>, ssh-<algorithm> <key2>".
|
||||
; ; For more information see "TrustedUserCAKeys" in the sshd config manpages.
|
||||
; SSH_TRUSTED_USER_CA_KEYS =
|
||||
; ; Absolute path of the `TrustedUserCaKeys` file gitea will manage.
|
||||
; ; Default this `RUN_USER`/.ssh/gitea-trusted-user-ca-keys.pem
|
||||
; ; If you're running your own ssh server and you want to use the gitea managed file you'll also need to modify your
|
||||
; ; sshd_config to point to this file. The official docker image will automatically work without further configuration.
|
||||
; SSH_TRUSTED_USER_CA_KEYS_FILENAME =
|
||||
; ;
|
||||
; ; Enable exposure of SSH clone URL to anonymous visitors, default is false
|
||||
; SSH_EXPOSE_ANONYMOUS = false
|
||||
; ;
|
||||
; ; Timeout for any write to ssh connections. (Set to -1 to disable all timeouts.)
|
||||
; ; Will default to the PER_WRITE_TIMEOUT.
|
||||
; SSH_PER_WRITE_TIMEOUT = 30s
|
||||
; ;
|
||||
; ; Timeout per Kb written to ssh connections.
|
||||
; ; Will default to the PER_WRITE_PER_KB_TIMEOUT.
|
||||
; SSH_PER_WRITE_PER_KB_TIMEOUT = 30s
|
||||
; ;
|
||||
; ; Indicate whether to check minimum key size with corresponding type
|
||||
; MINIMUM_KEY_SIZE_CHECK = false
|
||||
; ;
|
||||
; ; Disable CDN even in "prod" mode
|
||||
; OFFLINE_MODE = true
|
||||
; ;
|
||||
; ; TLS Settings: Either ACME or manual
|
||||
; ; (Other common TLS configuration are found before)
|
||||
; ENABLE_ACME = false
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; ACME automatic TLS settings
|
||||
; ;
|
||||
; ; ACME directory URL (e.g. LetsEncrypt's staging/testing URL: https://acme-staging-v02.api.letsencrypt.org/directory)
|
||||
; ; Leave empty to default to LetsEncrypt's (production) URL
|
||||
; ACME_URL =
|
||||
; ;
|
||||
; ; Explicitly accept the ACME's TOS. The specific TOS cannot be retrieved at the moment.
|
||||
; ACME_ACCEPTTOS = false
|
||||
; ;
|
||||
; ; If the ACME CA is not in your system's CA trust chain, it can be manually added here
|
||||
; ACME_CA_ROOT =
|
||||
; ;
|
||||
; ; Email used for the ACME registration service
|
||||
; ; Can be left blank to initialize at first run and use the cached value
|
||||
; ACME_EMAIL =
|
||||
; ;
|
||||
; ; ACME live directory (not to be confused with ACME directory URL: ACME_URL)
|
||||
; ; (Refer to caddy's ACME manager https://github.com/caddyserver/certmagic)
|
||||
; ACME_DIRECTORY = https
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; Manual TLS settings: (Only applicable if ENABLE_ACME=false)
|
||||
; ;
|
||||
; ; Generate steps:
|
||||
; ; $ ./gitea cert -ca=true -duration=8760h0m0s -host=myhost.example.com
|
||||
; ;
|
||||
; ; Or from a .pfx file exported from the Windows certificate store (do
|
||||
; ; not forget to export the private key):
|
||||
; ; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys
|
||||
; ; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes
|
||||
; ; Paths are relative to CUSTOM_PATH
|
||||
; CERT_FILE = https/cert.pem
|
||||
; KEY_FILE = https/key.pem
|
||||
; ;
|
||||
; ; Root directory containing templates and static files.
|
||||
; ; default is the path where Gitea is executed
|
||||
; STATIC_ROOT_PATH = ; Will default to the built-in value _`StaticRootPath`_
|
||||
; ;
|
||||
; ; Default path for App data
|
||||
; APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_
|
||||
; ;
|
||||
; ; Base path for App's temp files, leave empty to use the managed tmp directory in APP_DATA_PATH
|
||||
; APP_TEMP_PATH =
|
||||
; ;
|
||||
; ; Enable gzip compression for runtime-generated content, static resources excluded
|
||||
; ENABLE_GZIP = false
|
||||
; ;
|
||||
; ; Application profiling (memory and cpu)
|
||||
; ; For "web" command it listens on localhost:6060
|
||||
; ; For "serve" command it dumps to disk at PPROF_DATA_PATH as (cpuprofile|memprofile)_<username>_<temporary id>
|
||||
; ENABLE_PPROF = false
|
||||
; ;
|
||||
; ; PPROF_DATA_PATH, use an absolute path when you start gitea as service
|
||||
; PPROF_DATA_PATH = data/tmp/pprof ; Path is relative to _`AppWorkPath`_
|
||||
; ;
|
||||
; ; Landing page, can be "home", "explore", "organizations", "login", or any URL such as "/org/repo" or even "https://anotherwebsite.com"
|
||||
; ; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in.
|
||||
; LANDING_PAGE = home
|
||||
; ;
|
||||
; ; Enables git-lfs support. true or false, default is false.
|
||||
; LFS_START_SERVER = false
|
||||
; ;
|
||||
; ; Enables git-lfs SSH protocol support. true or false, default is false.
|
||||
; LFS_ALLOW_PURE_SSH = false
|
||||
; ;
|
||||
; ; LFS authentication secret, change this yourself
|
||||
; LFS_JWT_SECRET =
|
||||
; ;
|
||||
; ; Alternative location to specify LFS authentication secret. You cannot specify both this and LFS_JWT_SECRET, and must pick one
|
||||
; LFS_JWT_SECRET_URI = file:/etc/gitea/lfs_jwt_secret
|
||||
; ;
|
||||
; ; LFS authentication validity period (in time.Duration), pushes taking longer than this may fail.
|
||||
; LFS_HTTP_AUTH_EXPIRY = 24h
|
||||
; ;
|
||||
; ; Maximum allowed LFS file size in bytes (Set to 0 for no limit).
|
||||
; LFS_MAX_FILE_SIZE = 0
|
||||
; ;
|
||||
; ; Maximum number of locks returned per page
|
||||
; LFS_LOCKS_PAGING_NUM = 50
|
||||
; ;
|
||||
; ; When clients make lfs batch requests, reject them if there are more pointers than this number
|
||||
; ; zero means 'unlimited'
|
||||
; LFS_MAX_BATCH_SIZE = 0
|
||||
; ;
|
||||
; ; Allow graceful restarts using SIGHUP to fork
|
||||
; ALLOW_GRACEFUL_RESTARTS = true
|
||||
; ;
|
||||
; ; After a restart the parent will finish ongoing requests before
|
||||
; ; shutting down. Force shutdown if this process takes longer than this delay.
|
||||
; ; set to a negative value to disable
|
||||
; GRACEFUL_HAMMER_TIME = 60s
|
||||
; ;
|
||||
; ; Allows the setting of a startup timeout and waithint for Windows as SVC service
|
||||
; ; 0 disables this.
|
||||
; STARTUP_TIMEOUT = 0
|
||||
; ;
|
||||
; ; Static resources, includes resources on custom/, public/ and all uploaded avatars web browser cache time. Note that this cache is disabled when RUN_MODE is "dev". Default is 6h
|
||||
; STATIC_CACHE_TIME = 6h
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[database]
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; Database to use. Either "mysql", "postgres", "mssql" or "sqlite3".
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; MySQL Configuration
|
||||
; ;
|
||||
; DB_TYPE = mysql
|
||||
; HOST = 127.0.0.1:3306 ; can use socket e.g. /var/run/mysqld/mysqld.sock
|
||||
; NAME = gitea
|
||||
; USER = root
|
||||
; PASSWD = ;Use PASSWD = `your password` for quoting if you use special characters in the password.
|
||||
; SSL_MODE = false ; either "false" (default), "true", or "skip-verify"
|
||||
; CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need.
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; Postgres Configuration
|
||||
; ;
|
||||
; DB_TYPE = postgres
|
||||
; HOST = 127.0.0.1:5432 ; can use socket e.g. /var/run/postgresql/
|
||||
; NAME = gitea
|
||||
; USER = root
|
||||
; PASSWD =
|
||||
; SCHEMA =
|
||||
; SSL_MODE=disable ;either "disable" (default), "require", or "verify-full"
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; SQLite Configuration
|
||||
; ;
|
||||
DB_TYPE = sqlite3
|
||||
; defaults to data/gitea.db
|
||||
PATH = /var/lib/gitea/data/gitea.db
|
||||
; Query timeout defaults to: 500
|
||||
SQLITE_TIMEOUT =
|
||||
; defaults to sqlite database default (often DELETE), can be used to enable WAL mode. https://www.sqlite.org/pragma.html#pragma_journal_mode
|
||||
SQLITE_JOURNAL_MODE =
|
||||
HOST = 127.0.0.1:3306
|
||||
NAME = gitea
|
||||
USER = gitea
|
||||
PASSWD =
|
||||
SCHEMA =
|
||||
SSL_MODE = disable
|
||||
LOG_SQL = false
|
||||
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; MSSQL Configuration
|
||||
; ;
|
||||
; DB_TYPE = mssql
|
||||
; HOST = 172.17.0.2:1433
|
||||
; NAME = gitea
|
||||
; USER = SA
|
||||
; PASSWD = MwantsaSecurePassword1
|
||||
; CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need.
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; Other settings
|
||||
; ;
|
||||
; ; For iterate buffer, default is 50
|
||||
; ITERATE_BUFFER_SIZE = 50
|
||||
; ;
|
||||
; ; Show the database generated SQL
|
||||
; LOG_SQL = false
|
||||
; ;
|
||||
; ; Maximum number of DB Connect retries
|
||||
; DB_RETRIES = 10
|
||||
; ;
|
||||
; ; Backoff time per DB retry (time.Duration)
|
||||
; DB_RETRY_BACKOFF = 3s
|
||||
; ;
|
||||
; ; Max idle database connections on connection pool, default is 2
|
||||
; MAX_IDLE_CONNS = 2
|
||||
; ;
|
||||
; ; Database connection max life time, default is 0 or 3s mysql (See #6804 & #7071 for reasoning)
|
||||
; CONN_MAX_LIFETIME = 3s
|
||||
; ;
|
||||
; ; Database maximum number of open connections, default is 0 meaning no maximum
|
||||
; MAX_OPEN_CONNS = 0
|
||||
; ;
|
||||
; ; Whether execute database models migrations automatically
|
||||
; AUTO_MIGRATION = true
|
||||
; ;
|
||||
; ; Threshold value (in seconds) beyond which query execution time is logged as a warning in the xorm logger
|
||||
; ;
|
||||
; SLOW_QUERY_THRESHOLD = 5s
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[security]
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; Whether the installer is disabled (set to true to disable the installer)
|
||||
INSTALL_LOCK = true
|
||||
; ;
|
||||
; ; Global secret key that will be used
|
||||
; ; This key is VERY IMPORTANT. If you lose it, the data encrypted by it (like 2FA secret) can't be decrypted anymore.
|
||||
SECRET_KEY =
|
||||
; ;
|
||||
; ; Alternative location to specify secret key, instead of this file; you cannot specify both this and SECRET_KEY, and must pick one
|
||||
; ; This key is VERY IMPORTANT. If you lose it, the data encrypted by it (like 2FA secret) can't be decrypted anymore.
|
||||
; SECRET_KEY_URI = file:/etc/gitea/secret_key
|
||||
; ;
|
||||
; ; Secret used to validate communication within Gitea binary.
|
||||
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3NzM4MjYzMzJ9.XxUurNQ5drHXpepExUTNEtYS4yLpTdac_fGOeL0eVco
|
||||
PASSWORD_HASH_ALGO = pbkdf2
|
||||
|
||||
; ;
|
||||
; ; Alternative location to specify internal token, instead of this file; you cannot specify both this and INTERNAL_TOKEN, and must pick one
|
||||
; INTERNAL_TOKEN_URI = file:/etc/gitea/internal_token
|
||||
; ;
|
||||
; ; How long to remember that a user is logged in before requiring relogin (in days)
|
||||
; LOGIN_REMEMBER_DAYS = 31
|
||||
; ;
|
||||
; ; Name of the cookie used to store the current username.
|
||||
; COOKIE_USERNAME = gitea_awesome
|
||||
; ;
|
||||
; ; Name of cookie used to store authentication information.
|
||||
; COOKIE_REMEMBER_NAME = gitea_incredible
|
||||
; ;
|
||||
; ; Reverse proxy authentication header name of user name, email, and full name
|
||||
; REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
|
||||
; REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL
|
||||
; REVERSE_PROXY_AUTHENTICATION_FULL_NAME = X-WEBAUTH-FULLNAME
|
||||
; ;
|
||||
; ; Interpret X-Forwarded-For header or the X-Real-IP header and set this as the remote IP for the request
|
||||
; REVERSE_PROXY_LIMIT = 1
|
||||
; ;
|
||||
; ; List of IP addresses and networks separated by comma of trusted proxy servers. Use `*` to trust all.
|
||||
; REVERSE_PROXY_TRUSTED_PROXIES = 127.0.0.0/8,::1/128
|
||||
; ;
|
||||
; ; The minimum password length for new Users
|
||||
; MIN_PASSWORD_LENGTH = 8
|
||||
; ;
|
||||
; ; Set to true to allow users to import local server paths
|
||||
; IMPORT_LOCAL_PATHS = false
|
||||
; ;
|
||||
; ; Set to false to allow users with git hook privileges to create custom git hooks.
|
||||
; ; Custom git hooks can be used to perform arbitrary code execution on the host operating system.
|
||||
; ; This enables the users to access and modify this config file and the Gitea database and interrupt the Gitea service.
|
||||
; ; By modifying the Gitea database, users can gain Gitea administrator privileges.
|
||||
; ; It also enables them to access other resources available to the user on the operating system that is running the Gitea instance and perform arbitrary actions in the name of the Gitea OS user.
|
||||
; ; WARNING: This maybe harmful to you website or your operating system.
|
||||
; ; WARNING: Setting this to true does not change existing hooks in git repos; adjust it before if necessary.
|
||||
; DISABLE_GIT_HOOKS = true
|
||||
; ;
|
||||
; ; Set to true to disable webhooks feature.
|
||||
; DISABLE_WEBHOOKS = false
|
||||
; ;
|
||||
; ; Set to false to allow pushes to gitea repositories despite having an incomplete environment - NOT RECOMMENDED
|
||||
; ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET = true
|
||||
; ;
|
||||
; ;Comma separated list of character classes required to pass minimum complexity.
|
||||
; ;If left empty or no valid values are specified, the default is off (no checking)
|
||||
; ;Classes include "lower,upper,digit,spec"
|
||||
; PASSWORD_COMPLEXITY = off
|
||||
; ;
|
||||
; ; Password Hash algorithm, either "argon2", "pbkdf2", "scrypt" or "bcrypt"
|
||||
; PASSWORD_HASH_ALGO = pbkdf2
|
||||
; ;
|
||||
; ; Set false to allow JavaScript to read CSRF cookie
|
||||
; CSRF_COOKIE_HTTP_ONLY = true
|
||||
; ;
|
||||
; ; Validate against https://haveibeenpwned.com/Passwords to see if a password has been exposed
|
||||
; PASSWORD_CHECK_PWN = false
|
||||
; ;
|
||||
; ; Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations.
|
||||
; ; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
||||
; SUCCESSFUL_TOKENS_CACHE_SIZE = 20
|
||||
; ;
|
||||
; ; Reject API tokens sent in URL query string (Accept Header-based API tokens only). This avoids security vulnerabilities
|
||||
; ; stemming from cached/logged plain-text API tokens.
|
||||
; ; In future releases, this will become the default behavior
|
||||
; DISABLE_QUERY_AUTH_TOKEN = false
|
||||
; ;
|
||||
; ; On user registration, record the IP address and user agent of the user to help identify potential abuse.
|
||||
; ; RECORD_USER_SIGNUP_METADATA = false
|
||||
; ;
|
||||
; ; Set the two-factor auth behavior.
|
||||
; ; Set to "enforced", to force users to enroll into Two-Factor Authentication, users without 2FA have no access to repositories via API or web.
|
||||
; TWO_FACTOR_AUTH =
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[camo]
|
||||
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; At the moment we only support images
|
||||
; ;
|
||||
; ; if the camo is enabled
|
||||
; ENABLED = false
|
||||
; ; url to a camo image proxy, it **is required** if camo is enabled.
|
||||
; SERVER_URL =
|
||||
; ; HMAC to encode urls with, it **is required** if camo is enabled.
|
||||
; HMAC_KEY =
|
||||
; ; Set to true to use camo for https too lese only non https urls are proxyed
|
||||
; ; ALLWAYS is deprecated and will be removed in the future
|
||||
; ALWAYS = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[oauth2]
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; Enables OAuth2 provider
|
||||
ENABLED = true
|
||||
JWT_SECRET = tU0mvpYYFatn8ZJ45ZnuA4RLy6kogrerIblDbihu8oU
|
||||
|
||||
; ;
|
||||
; ; Algorithm used to sign OAuth2 tokens. Valid values: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, EdDSA
|
||||
; JWT_SIGNING_ALGORITHM = RS256
|
||||
; ;
|
||||
; ; Private key file path used to sign OAuth2 tokens. The path is relative to APP_DATA_PATH.
|
||||
; ; This setting is only needed if JWT_SIGNING_ALGORITHM is set to RS256, RS384, RS512, ES256, ES384 or ES512.
|
||||
; ; The file must contain a RSA or ECDSA private key in the PKCS8 format. If no key exists a 4096 bit key will be created for you.
|
||||
; JWT_SIGNING_PRIVATE_KEY_FILE = jwt/private.pem
|
||||
; ;
|
||||
; ; OAuth2 authentication secret for access and refresh tokens, change this yourself to a unique string. CLI generate option is helpful in this case. https://docs.gitea.io/en-us/command-line/#generate
|
||||
; ; This setting is only needed if JWT_SIGNING_ALGORITHM is set to HS256, HS384 or HS512.
|
||||
; JWT_SECRET =
|
||||
; ;
|
||||
; ; Alternative location to specify OAuth2 authentication secret. You cannot specify both this and JWT_SECRET, and must pick one
|
||||
; JWT_SECRET_URI = file:/etc/gitea/oauth2_jwt_secret
|
||||
; ;
|
||||
; ; The "issuer" claim identifies the principal that issued the JWT.
|
||||
; ; Gitea 1.25 makes it default to "ROOT_URL without the last slash" to follow the standard.
|
||||
; ; If you have old logins from before 1.25, you may want to set it to the old (non-standard) value "ROOT_URL with the last slash".
|
||||
; JWT_CLAIM_ISSUER =
|
||||
; ;
|
||||
; ; Lifetime of an OAuth2 access token in seconds
|
||||
; ACCESS_TOKEN_EXPIRATION_TIME = 3600
|
||||
; ;
|
||||
; ; Lifetime of an OAuth2 refresh token in hours
|
||||
; REFRESH_TOKEN_EXPIRATION_TIME = 730
|
||||
; ;
|
||||
; ; Check if refresh token got already used
|
||||
; INVALIDATE_REFRESH_TOKENS = false
|
||||
; ;
|
||||
; ; Maximum length of oauth2 token/cookie stored on server
|
||||
; MAX_TOKEN_LENGTH = 32767
|
||||
; ;
|
||||
; ; Pre-register OAuth2 applications for some universally useful services
|
||||
; ; * https://github.com/hickford/git-credential-oauth
|
||||
; ; * https://github.com/git-ecosystem/git-credential-manager
|
||||
; ; * https://gitea.com/gitea/tea
|
||||
; DEFAULT_APPLICATIONS = git-credential-oauth, git-credential-manager, tea
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[log]
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ; Root path for the log files - defaults to "{AppWorkPath}/log"
|
||||
; ROOT_PATH =
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ; Main Logger
|
||||
; ;
|
||||
; ; Either "console", "file" or "conn", default is "console"
|
||||
; ; Use comma to separate multiple modes, e.g. "console, file"
|
||||
MODE = console
|
||||
; ;
|
||||
; ; Either "Trace", "Debug", "Info", "Warn", "Error" or "None", default is "Info"
|
||||
LEVEL = info
|
||||
ROOT_PATH = /var/lib/gitea/log
|
||||
|
||||
; ;
|
||||
; ; Print Stacktrace with logs (rarely helpful, do not set) Either "Trace", "Debug", "Info", "Warn", "Error", default is "None"
|
||||
; STACKTRACE_LEVEL = None
|
||||
; ;
|
||||
; ; Buffer length of the channel, keep it as it is if you don't know what it is.
|
||||
; BUFFER_LEN = 10000
|
||||
; ;
|
||||
; ; Sub logger modes, a single comma means use default MODE above, empty means disable it
|
||||
; logger.access.MODE=
|
||||
; logger.router.MODE=,
|
||||
; logger.xorm.MODE=,
|
||||
; ;
|
||||
; ; Collect SSH logs (Creates log from ssh git request)
|
||||
; ;
|
||||
; ENABLE_SSH_LOG = false
|
||||
; ;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; Access Logger (Creates log in NCSA common log format)
|
||||
; ;
|
||||
; ; Print request id which parsed from request headers in access log, when access log is enabled.
|
||||
; ; * E.g:
|
||||
; ; * In request Header: X-Request-ID: test-id-123
|
||||
; ; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID
|
||||
; ; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "test-id-123"
|
||||
; ;
|
||||
; ; If you configure more than one in the .ini file, it will match in the order of configuration,
|
||||
; ; and the first match will be finally printed in the log.
|
||||
; ; * E.g:
|
||||
; ; * In request Header: X-Trace-ID: trace-id-1q2w3e4r
|
||||
; ; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID, X-Trace-ID, X-Req-ID
|
||||
; ; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "trace-id-1q2w3e4r"
|
||||
; ;
|
||||
; REQUEST_ID_HEADERS =
|
||||
; ;
|
||||
; ; Sets the template used to create the access log.
|
||||
; ACCESS_LOG_TEMPLATE = {{.Ctx.RemoteHost}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}" "{{.Ctx.Req.UserAgent}}"
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; Log modes (aka log writers)
|
||||
; ;
|
||||
; [log.%(WriterMode)]
|
||||
; MODE=console/file/conn/...
|
||||
; LEVEL=
|
||||
; FLAGS = stdflags
|
||||
; EXPRESSION =
|
||||
; PREFIX =
|
||||
; COLORIZE = false
|
||||
; ;
|
||||
; [log.console]
|
||||
; STDERR = false
|
||||
; ;
|
||||
; [log.file]
|
||||
; ; Set the file_name for the logger. If this is a relative path this will be relative to ROOT_PATH
|
||||
; FILE_NAME =
|
||||
; ; This enables automated log rotate(switch of following options), default is true
|
||||
; LOG_ROTATE = true
|
||||
; ; Max size shift of a single file, default is 28 means 1 << 28, 256MB
|
||||
; MAX_SIZE_SHIFT = 28
|
||||
; ; Segment log daily, default is true
|
||||
; DAILY_ROTATE = true
|
||||
; ; delete the log file after n days, default is 7
|
||||
; MAX_DAYS = 7
|
||||
; ; compress logs with gzip
|
||||
; COMPRESS = true
|
||||
; ; compression level see godoc for compress/gzip
|
||||
; COMPRESSION_LEVEL = -1
|
||||
; ;
|
||||
; [log.conn]
|
||||
; ; Reconnect host for every single message, default is false
|
||||
; RECONNECT_ON_MSG = false
|
||||
; ; Try to reconnect when connection is lost, default is false
|
||||
; RECONNECT = false
|
||||
; ; Either "tcp", "unix" or "udp", default is "tcp"
|
||||
; PROTOCOL = tcp
|
||||
; ; Host address
|
||||
; ADDR =
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[git]
|
||||
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;
|
||||
; ; The path of git executable. If empty, Gitea searches through the PATH environment.
|
||||
; PATH =
|
||||
; ;
|
||||
; ; The HOME directory for Git, defaults to "{APP_DATA_PATH}/home"
|
||||
; HOME_PATH =
|
||||
; ;
|
||||
; ; Disables highlight of added and removed changes
|
||||
; DISABLE_DIFF_HIGHLIGHT = false
|
||||
; ;
|
||||
; ; Max number of lines allowed in a single file in diff view
|
||||
; MAX_GIT_DIFF_LINES = 1000
|
||||
; ;
|
||||
; ; Max number of allowed characters in a line in diff view
|
||||
; MAX_GIT_DIFF_LINE_CHARACTERS = 5000
|
||||
; ;
|
||||
; ; Max number of files shown in diff view
|
||||
; MAX_GIT_DIFF_FILES = 100
|
||||
; ;
|
||||
; ; Set the default commits range size
|
||||
; COMMITS_RANGE_SIZE = 50
|
||||
; ;
|
||||
; ; Set the default branches range size
|
||||
; BRANCHES_RANGE_SIZE = 20
|
||||
; ;
|
||||
; ; Arguments for command 'git gc', e.g. "--aggressive --auto"
|
||||
; ; see more on http://git-scm.com/docs/git-gc/
|
||||
; GC_ARGS =
|
||||
; ;
|
||||
; ; If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1
|
||||
; ; To enable this for Git over SSH when using a OpenSSH server, add `AcceptEnv GIT_PROTOCOL` to your sshd_config file.
|
||||
; ENABLE_AUTO_GIT_WIRE_PROTOCOL = true
|
||||
; ;
|
||||
; ; Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled)
|
||||
; PULL_REQUEST_PUSH_MESSAGE = true
|
||||
; ;
|
||||
; ; (Go-Git only) Don't cache objects greater than this in memory. (Set to 0 to disable.)
|
||||
; LARGE_OBJECT_THRESHOLD = 1048576
|
||||
; ; Set to true to forcibly set core.protectNTFS=false
|
||||
; DISABLE_CORE_PROTECT_NTFS=false
|
||||
; ; Disable the usage of using partial clones for git.
|
||||
; DISABLE_PARTIAL_CLONE = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ; Git Operation timeout in seconds
|
||||
; [git.timeout]
|
||||
; DEFAULT = 360
|
||||
; MIGRATE = 600
|
||||
; MIRROR = 300
|
||||
; CLONE = 300
|
||||
; PULL = 300
|
||||
; GC = 60
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ; Git config options
|
||||
; ; This section only does "set" config, a removed config key from this section won't be removed from git config automatically. The format is `some.configKey = value`.
|
||||
; [git.config]
|
||||
; diff.algorithm = histogram
|
||||
; core.logAllRefUpdates = true
|
||||
; gc.reflogExpire = 90
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[service]
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
DISABLE_REGISTRATION = false
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = true
|
||||
ENABLE_CAPTCHA = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = false
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
DEFAULT_USER_VISIBILITY = private
|
||||
DEFAULT_USER_IS_RESTRICTED = true
|
||||
NO_REPLY_ADDRESS = noreply.localhost
|
||||
|
||||
[repository]
|
||||
ROOT = /var/lib/gitea/data/gitea-repositories
|
||||
MAX_CREATION_LIMIT = 0
|
||||
|
||||
[lfs]
|
||||
PATH = /var/lib/gitea/data/lfs
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = true
|
||||
ENABLE_OPENID_SIGNUP = true
|
||||
|
||||
[cron.update_checker]
|
||||
ENABLED = false
|
||||
|
||||
[session]
|
||||
PROVIDER = file
|
||||
|
||||
[repository.pull-request]
|
||||
DEFAULT_MERGE_STYLE = merge
|
||||
|
||||
[repository.signing]
|
||||
DEFAULT_TRUST_MODEL = committer
|
||||
|
||||
[oauth2_client]
|
||||
ENABLE_AUTO_REGISTRATION = true
|
||||
ACCOUNT_LINKING = auto
|
||||
OPENID_CONNECT_SCOPES = profile email
|
||||
@@ -4,3 +4,6 @@ from django.apps import AppConfig
|
||||
class HomeConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "home"
|
||||
|
||||
def ready(self):
|
||||
import home.signals
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-17 11:46+0000\n"
|
||||
"POT-Creation-Date: 2026-03-20 12:18+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -18,6 +18,79 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:5
|
||||
msgid "Chat with"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:10
|
||||
msgid "Admin Chat View"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:11
|
||||
msgid ""
|
||||
"This is the admin view of the chat. Here you can manage conversations and "
|
||||
"monitor user interactions."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:19
|
||||
#: home/templates/chat/user_chat.html:18
|
||||
msgid "No messages found."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:24
|
||||
#: home/templates/chat/user_chat.html:23
|
||||
msgid "Type your message here..."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:25
|
||||
#: home/templates/chat/user_chat.html:24
|
||||
msgid "Send"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat_dashboard.html:5
|
||||
#: home/templates/chat/user_chat.html:5
|
||||
msgid "Chat"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat_dashboard.html:10
|
||||
msgid "Admin Chat Dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat_dashboard.html:19
|
||||
msgid "No active chats found."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/user_chat.html:9
|
||||
msgid "Chat with Support"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/user_chat.html:10
|
||||
msgid ""
|
||||
"This is the user chat interface. Here you can communicate with our support "
|
||||
"team for assistance."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_index_page.html:4
|
||||
#: home/templates/home/course_index_page.html:10
|
||||
msgid "Courses"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_index_page.html:12
|
||||
msgid "Purchased Courses"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_index_page.html:22
|
||||
msgid "Purchased"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_index_page.html:32
|
||||
msgid "Available Courses"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_index_page.html:42
|
||||
msgid "Not Purchased"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_module_page.html:21
|
||||
msgid "Lessons"
|
||||
msgstr ""
|
||||
@@ -26,36 +99,40 @@ msgstr ""
|
||||
msgid "No lessons yet."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_page.html:26
|
||||
msgid "Modules"
|
||||
#: home/templates/home/course_page.html:31
|
||||
msgid "Refund Purchase"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_page.html:33
|
||||
msgid "Modules"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_page.html:40
|
||||
msgid "No modules yet."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_page.html:39
|
||||
#: home/templates/home/course_page.html:46
|
||||
msgid ""
|
||||
"You need to be logged in to access this course. Please log in or sign up to "
|
||||
"view the modules."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_page.html:40
|
||||
#: home/templates/home/course_page.html:47
|
||||
#: home/templates/home/event_page.html:40
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_page.html:41
|
||||
#: home/templates/home/course_page.html:48
|
||||
#: home/templates/home/event_page.html:43
|
||||
msgid "Sign Up"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_page.html:46
|
||||
#: home/templates/home/course_page.html:53
|
||||
msgid ""
|
||||
"You don't have access to this course. Please purchase it to view the modules."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/course_page.html:47
|
||||
#: home/templates/home/course_page.html:54
|
||||
msgid "Purchase Course"
|
||||
msgstr ""
|
||||
|
||||
@@ -91,46 +168,3 @@ msgstr ""
|
||||
#: home/templates/home/event_page.html:54
|
||||
msgid "Sign Up for Event"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:6
|
||||
msgid "Visit the Wagtail website"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:15
|
||||
msgid "View the release notes"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:27
|
||||
msgid "Welcome to your new Wagtail site!"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:28
|
||||
msgid ""
|
||||
"Please feel free to <a href=\"https://github.com/wagtail/wagtail/wiki/"
|
||||
"Slack\">join our community on Slack</a>, or get started with one of the "
|
||||
"links below."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:35
|
||||
msgid "Wagtail Documentation"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:36
|
||||
msgid "Topics, references, & how-tos"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:42
|
||||
msgid "Tutorial"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:43
|
||||
msgid "Build your first Wagtail site"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:49
|
||||
msgid "Admin Interface"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:50
|
||||
msgid "Create your superuser first!"
|
||||
msgstr ""
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-17 11:46+0000\n"
|
||||
"POT-Creation-Date: 2026-03-20 12:18+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -20,25 +20,102 @@ msgstr ""
|
||||
"(n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && "
|
||||
"n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:5
|
||||
msgid "Chat with"
|
||||
msgstr "Czat z"
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:10
|
||||
msgid "Admin Chat View"
|
||||
msgstr "Widok administratora czatu"
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:11
|
||||
msgid ""
|
||||
"This is the admin view of the chat. Here you can manage conversations and "
|
||||
"monitor user interactions."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:19
|
||||
#: home/templates/chat/user_chat.html:18
|
||||
msgid "No messages found."
|
||||
msgstr "Brak wiadomości."
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:24
|
||||
#: home/templates/chat/user_chat.html:23
|
||||
msgid "Type your message here..."
|
||||
msgstr "Wiadomość..."
|
||||
|
||||
#: home/templates/chat/admin/admin_chat.html:25
|
||||
#: home/templates/chat/user_chat.html:24
|
||||
msgid "Send"
|
||||
msgstr "Wyślij"
|
||||
|
||||
#: home/templates/chat/admin/admin_chat_dashboard.html:5
|
||||
#: home/templates/chat/user_chat.html:5
|
||||
msgid "Chat"
|
||||
msgstr "Czat"
|
||||
|
||||
#: home/templates/chat/admin/admin_chat_dashboard.html:10
|
||||
msgid "Admin Chat Dashboard"
|
||||
msgstr "Panel administratora czatu"
|
||||
|
||||
#: home/templates/chat/admin/admin_chat_dashboard.html:19
|
||||
msgid "No active chats found."
|
||||
msgstr "Brak aktywnych czatów."
|
||||
|
||||
#: home/templates/chat/user_chat.html:9
|
||||
msgid "Chat with Support"
|
||||
msgstr "Czat z administracją"
|
||||
|
||||
#: home/templates/chat/user_chat.html:10
|
||||
msgid ""
|
||||
"This is the user chat interface. Here you can communicate with our support "
|
||||
"team for assistance."
|
||||
msgstr ""
|
||||
"To jest interfejs czatu dla użytkowników. Tutaj możesz komunikować się z "
|
||||
"naszym zespołem wsparcia w celu uzyskania pomocy."
|
||||
|
||||
#: home/templates/home/course_index_page.html:4
|
||||
#: home/templates/home/course_index_page.html:10
|
||||
msgid "Courses"
|
||||
msgstr "Kursy"
|
||||
|
||||
#: home/templates/home/course_index_page.html:12
|
||||
msgid "Purchased Courses"
|
||||
msgstr "Zakupione kursy"
|
||||
|
||||
#: home/templates/home/course_index_page.html:22
|
||||
msgid "Purchased"
|
||||
msgstr "Zakupiony"
|
||||
|
||||
#: home/templates/home/course_index_page.html:32
|
||||
msgid "Available Courses"
|
||||
msgstr "Dostępne kursy"
|
||||
|
||||
#: home/templates/home/course_index_page.html:42
|
||||
msgid "Not Purchased"
|
||||
msgstr "Niezakupiony"
|
||||
|
||||
#: home/templates/home/course_module_page.html:21
|
||||
msgid "Lessons"
|
||||
msgstr "Lekcje"
|
||||
|
||||
#: home/templates/home/course_module_page.html:28
|
||||
#, fuzzy
|
||||
#| msgid "No modules yet."
|
||||
msgid "No lessons yet."
|
||||
msgstr "Brak lekcji."
|
||||
|
||||
#: home/templates/home/course_page.html:26
|
||||
#: home/templates/home/course_page.html:31
|
||||
msgid "Refund Purchase"
|
||||
msgstr "Zwróć zakup"
|
||||
|
||||
#: home/templates/home/course_page.html:33
|
||||
msgid "Modules"
|
||||
msgstr "Moduły"
|
||||
|
||||
#: home/templates/home/course_page.html:33
|
||||
#: home/templates/home/course_page.html:40
|
||||
msgid "No modules yet."
|
||||
msgstr "Brak modułów."
|
||||
|
||||
#: home/templates/home/course_page.html:39
|
||||
#: home/templates/home/course_page.html:46
|
||||
msgid ""
|
||||
"You need to be logged in to access this course. Please log in or sign up to "
|
||||
"view the modules."
|
||||
@@ -46,22 +123,22 @@ msgstr ""
|
||||
"Musisz być zalogowany, aby uzyskać dostęp do tego kursu. Zaloguj się lub "
|
||||
"zarejestruj, aby zobaczyć moduły."
|
||||
|
||||
#: home/templates/home/course_page.html:40
|
||||
#: home/templates/home/course_page.html:47
|
||||
#: home/templates/home/event_page.html:40
|
||||
msgid "Login"
|
||||
msgstr "Zaloguj się"
|
||||
|
||||
#: home/templates/home/course_page.html:41
|
||||
#: home/templates/home/course_page.html:48
|
||||
#: home/templates/home/event_page.html:43
|
||||
msgid "Sign Up"
|
||||
msgstr "Zarejestruj się"
|
||||
|
||||
#: home/templates/home/course_page.html:46
|
||||
#: home/templates/home/course_page.html:53
|
||||
msgid ""
|
||||
"You don't have access to this course. Please purchase it to view the modules."
|
||||
msgstr "Nie masz dostępu do tego kursu. Zakup go, aby zobaczyć moduły."
|
||||
|
||||
#: home/templates/home/course_page.html:47
|
||||
#: home/templates/home/course_page.html:54
|
||||
msgid "Purchase Course"
|
||||
msgstr "Kup kurs"
|
||||
|
||||
@@ -105,46 +182,3 @@ msgstr ""
|
||||
#: home/templates/home/event_page.html:54
|
||||
msgid "Sign Up for Event"
|
||||
msgstr "Zapisz się"
|
||||
|
||||
#: home/templates/home/welcome_page.html:6
|
||||
msgid "Visit the Wagtail website"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:15
|
||||
msgid "View the release notes"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:27
|
||||
msgid "Welcome to your new Wagtail site!"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:28
|
||||
msgid ""
|
||||
"Please feel free to <a href=\"https://github.com/wagtail/wagtail/wiki/"
|
||||
"Slack\">join our community on Slack</a>, or get started with one of the "
|
||||
"links below."
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:35
|
||||
msgid "Wagtail Documentation"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:36
|
||||
msgid "Topics, references, & how-tos"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:42
|
||||
msgid "Tutorial"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:43
|
||||
msgid "Build your first Wagtail site"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:49
|
||||
msgid "Admin Interface"
|
||||
msgstr ""
|
||||
|
||||
#: home/templates/home/welcome_page.html:50
|
||||
msgid "Create your superuser first!"
|
||||
msgstr ""
|
||||
|
||||
25
home/migrations/0018_courseindexpage.py
Normal file
25
home/migrations/0018_courseindexpage.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 6.0.3 on 2026-03-19 14:41
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0017_chatmessage'),
|
||||
('wagtailcore', '0096_referenceindex_referenceindex_source_object_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CourseIndexPage',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
]
|
||||
18
home/migrations/0019_coursepage_description.py
Normal file
18
home/migrations/0019_coursepage_description.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 6.0.3 on 2026-03-19 15:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0018_courseindexpage'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='coursepage',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
]
|
||||
25
home/migrations/0020_coursepage_repository_url_and_more.py
Normal file
25
home/migrations/0020_coursepage_repository_url_and_more.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 6.0.3 on 2026-03-23 11:59
|
||||
|
||||
import modelcluster.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
('home', '0019_coursepage_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='coursepage',
|
||||
name='repository_url',
|
||||
field=models.URLField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='coursepage',
|
||||
name='allowed_groups',
|
||||
field=modelcluster.fields.ParentalManyToManyField(help_text="Additional groups that should have access to this course, e.g. Editors. NOTE: Users who purchase the course will be automatically added to a dedicated access group for this course, so you don't need to add that group here.", related_name='course_pages', to='auth.group'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 6.0.3 on 2026-03-30 07:51
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0020_coursepage_repository_url_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='modulelessonpage',
|
||||
name='create_gitea_repo',
|
||||
field=models.BooleanField(default=False, help_text='If enabled, a Gitea repository will be automatically created for this module when the module is published.'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='modulelessonpage',
|
||||
name='gitea_repo_url',
|
||||
field=models.URLField(blank=True, help_text="URL of the Gitea repository for this lesson (auto-generated if 'create_gitea_repo' is enabled)", null=True),
|
||||
),
|
||||
]
|
||||
40
home/migrations/0022_blogindexpage_blogpage.py
Normal file
40
home/migrations/0022_blogindexpage_blogpage.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Generated by Django 6.0.3 on 2026-03-30 07:53
|
||||
|
||||
import django.db.models.deletion
|
||||
import wagtail.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0021_modulelessonpage_create_gitea_repo_and_more'),
|
||||
('wagtailcore', '0096_referenceindex_referenceindex_source_object_and_more'),
|
||||
('wagtailimages', '0027_image_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BlogIndexPage',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BlogPage',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
|
||||
('author', models.CharField(max_length=255)),
|
||||
('body', wagtail.fields.StreamField([('heading', 0), ('paragraph', 1), ('image', 2)], block_lookup={0: ('wagtail.blocks.CharBlock', (), {'form_classname': 'title'}), 1: ('wagtail.blocks.RichTextBlock', (), {}), 2: ('wagtail.images.blocks.ImageBlock', [], {})})),
|
||||
('image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
]
|
||||
25
home/migrations/0023_eventindexpage.py
Normal file
25
home/migrations/0023_eventindexpage.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 6.0.3 on 2026-04-22 17:52
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0022_blogindexpage_blogpage'),
|
||||
('wagtailcore', '0096_referenceindex_referenceindex_source_object_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='EventIndexPage',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
]
|
||||
@@ -1,5 +1,6 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.db import models
|
||||
from django.forms import CheckboxSelectMultiple
|
||||
@@ -7,13 +8,17 @@ from django.utils import timezone
|
||||
from modelcluster.contrib.taggit import ClusterTaggableManager
|
||||
from modelcluster.fields import ParentalKey
|
||||
from taggit.models import TaggedItemBase
|
||||
from wagtail import blocks
|
||||
from wagtail.admin.panels import FieldPanel
|
||||
from wagtail.fields import RichTextField
|
||||
from wagtail.fields import RichTextField, StreamField
|
||||
from wagtail.images.blocks import ImageBlock
|
||||
from wagtail.models import Page
|
||||
from wagtail.models.copying import ParentalManyToManyField
|
||||
from wagtail_color_panel.edit_handlers import NativeColorPanel
|
||||
from wagtail_color_panel.fields import ColorField
|
||||
|
||||
from purchase.models import CoursePurchase
|
||||
|
||||
|
||||
class EmptyPage(Page):
|
||||
pass
|
||||
@@ -25,8 +30,67 @@ class HomePage(Page):
|
||||
content_panels = Page.content_panels + ["body"]
|
||||
|
||||
|
||||
class BlogIndexPage(Page):
|
||||
subpage_types = ["home.BlogPage"]
|
||||
|
||||
def get_context(self, request):
|
||||
context = super().get_context(request)
|
||||
context["posts"] = self.get_children().live().order_by("-first_published_at")
|
||||
return context
|
||||
|
||||
|
||||
class CourseIndexPage(Page):
|
||||
subpage_types = ["home.CoursePage"]
|
||||
|
||||
def get_context(self, request):
|
||||
context = super().get_context(request)
|
||||
all_courses = self.get_children().live()
|
||||
purchased_courses = set()
|
||||
other_courses = set()
|
||||
|
||||
for course in all_courses:
|
||||
if course.specific._user_has_access(request.user):
|
||||
purchased_courses.add(course)
|
||||
else:
|
||||
other_courses.add(course)
|
||||
|
||||
context["purchased_courses"] = sorted(
|
||||
purchased_courses, key=lambda c: c.title.lower()
|
||||
)
|
||||
context["other_courses"] = sorted(other_courses, key=lambda c: c.title.lower())
|
||||
return context
|
||||
|
||||
|
||||
class EventIndexPage(Page):
|
||||
subpage_types = ["home.EventPage"]
|
||||
|
||||
|
||||
class BlogPage(Page):
|
||||
author = models.CharField(max_length=255)
|
||||
image = models.ForeignKey(
|
||||
"wagtailimages.Image",
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="+",
|
||||
)
|
||||
body = StreamField(
|
||||
[
|
||||
("heading", blocks.CharBlock(classname="title")),
|
||||
("paragraph", blocks.RichTextBlock()),
|
||||
("image", ImageBlock()),
|
||||
]
|
||||
)
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
FieldPanel("author"),
|
||||
FieldPanel("image"),
|
||||
FieldPanel("body"),
|
||||
]
|
||||
parent_page_types = ["home.BlogIndexPage"]
|
||||
|
||||
|
||||
class CoursePage(Page):
|
||||
body = RichTextField(blank=True)
|
||||
course_image = models.ForeignKey(
|
||||
"wagtailimages.Image",
|
||||
null=True,
|
||||
@@ -34,28 +98,84 @@ class CoursePage(Page):
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="+",
|
||||
)
|
||||
description = models.CharField(max_length=255, blank=True)
|
||||
body = RichTextField(blank=True)
|
||||
allowed_groups = ParentalManyToManyField(
|
||||
Group,
|
||||
related_name="course_pages",
|
||||
help_text="Select a group to restrict access to this course. Non-members will be prompted to purchase the course to view modules.",
|
||||
help_text="Additional groups that should have access to this course, e.g. Editors. NOTE: Users who purchase the course will be automatically added to a dedicated access group for this course, so you don't need to add that group here.",
|
||||
)
|
||||
|
||||
repository_url = models.URLField(
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
def _user_has_access(self, user):
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
|
||||
user_group_ids = user.groups.values_list("id", flat=True)
|
||||
return self.allowed_groups.filter(id__in=user_group_ids).exists() # pyright: ignore[reportAttributeAccessIssue]
|
||||
if self.allowed_groups.filter(id__in=user_group_ids).exists():
|
||||
return True
|
||||
|
||||
return CoursePurchase.objects.filter(
|
||||
user=user, course=self, refunded=False
|
||||
).exists()
|
||||
|
||||
def _user_purchase_id(self, user):
|
||||
if not user.is_authenticated:
|
||||
return None
|
||||
|
||||
purchase = CoursePurchase.objects.filter(
|
||||
user=user, course=self, refunded=False
|
||||
).first()
|
||||
print(f"User {user} purchase for course {self}: {purchase}")
|
||||
return purchase.id if purchase else None
|
||||
|
||||
def mock_purchase(self, user):
|
||||
"""Mock method to simulate purchasing this course for a user."""
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
obj, created = CoursePurchase.objects.get_or_create(
|
||||
user=user, course=self, refunded=False
|
||||
)
|
||||
# Add user to dedicated access group for this course
|
||||
group_name = f"course_{self.id}_access"
|
||||
group, _ = Group.objects.get_or_create(name=group_name)
|
||||
user.groups.add(group)
|
||||
# Ensure allowed_groups only includes this access group
|
||||
if not self.allowed_groups.filter(id=group.id).exists():
|
||||
self.allowed_groups.add(group)
|
||||
return created
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.id is not None:
|
||||
group_name = f"course_{self.id}_access"
|
||||
group, created = Group.objects.get_or_create(name=group_name)
|
||||
if not self.allowed_groups.filter(id=group.id).exists():
|
||||
self.allowed_groups.add(group)
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_context(self, request):
|
||||
context = super().get_context(request)
|
||||
context["user_has_access"] = self._user_has_access(request.user)
|
||||
context["user_purchase_id"] = self._user_purchase_id(request.user)
|
||||
return context
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
FieldPanel("course_image"),
|
||||
FieldPanel("description"),
|
||||
FieldPanel("body"),
|
||||
FieldPanel("allowed_groups", widget=CheckboxSelectMultiple),
|
||||
FieldPanel(
|
||||
"repository_url",
|
||||
read_only=True,
|
||||
heading="Repository URL (auto-generated)",
|
||||
),
|
||||
]
|
||||
parent_page_types = ["home.CourseIndexPage"]
|
||||
subpage_types = ["home.CourseModulePage"]
|
||||
|
||||
|
||||
@@ -84,6 +204,23 @@ class CourseModulePage(Page):
|
||||
|
||||
class ModuleLessonPage(Page):
|
||||
body = RichTextField(blank=True)
|
||||
create_gitea_repo = models.BooleanField(
|
||||
default=False,
|
||||
help_text="If enabled, a Gitea repository will be automatically created for this module when the module is published.",
|
||||
)
|
||||
gitea_repo_url = models.URLField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="URL of the Gitea repository for this lesson (auto-generated if 'create_gitea_repo' is enabled)",
|
||||
)
|
||||
|
||||
@property
|
||||
def gitea_login_redirect_url(self):
|
||||
gitea_root_url = getattr(settings, "GITEA_ROOT_URL")
|
||||
if self.gitea_repo_url and gitea_root_url:
|
||||
uri = str(self.gitea_repo_url).replace(gitea_root_url, "")
|
||||
return f"{gitea_root_url}/user/login?redirect_to={uri}"
|
||||
return None
|
||||
|
||||
@property
|
||||
def module(self):
|
||||
@@ -100,7 +237,15 @@ class ModuleLessonPage(Page):
|
||||
return f"{module.full_title} - {self.title}"
|
||||
return self.title
|
||||
|
||||
content_panels = Page.content_panels + ["body"]
|
||||
content_panels = Page.content_panels + [
|
||||
FieldPanel("body"),
|
||||
FieldPanel("create_gitea_repo"),
|
||||
FieldPanel(
|
||||
"gitea_repo_url",
|
||||
read_only=True,
|
||||
heading="Gitea Repository URL",
|
||||
),
|
||||
]
|
||||
parent_page_types = ["home.CourseModulePage"]
|
||||
|
||||
|
||||
@@ -181,6 +326,8 @@ class EventPage(Page):
|
||||
help_text="Select users who will be listed as hosts of this event.",
|
||||
)
|
||||
|
||||
parent_page_types = ["home.EventIndexPage"]
|
||||
|
||||
def get_context(self, request):
|
||||
context = super().get_context(request)
|
||||
# Occurrence-specific context should be handled in views/templates
|
||||
@@ -191,15 +338,26 @@ class EventPage(Page):
|
||||
Generate EventOccurrence objects for this event based on recurrence settings.
|
||||
For endless recurrence, generate up to days_ahead into the future.
|
||||
"""
|
||||
from .event_occurrence import EventOccurrence
|
||||
|
||||
now = timezone.now()
|
||||
|
||||
if not self.live:
|
||||
# if not live, no future occurrences should be generated
|
||||
self.occurrences.filter(start__gt=now).delete()
|
||||
return
|
||||
|
||||
if not self.recurrence_enabled:
|
||||
# if recurrence is not enabled, ensure there's at least one occurrence for the specified start/end
|
||||
# and delete any other occurrences that don't match the current start/end
|
||||
if self.occurrences.exists():
|
||||
occurrence = self.occurrences.first()
|
||||
if occurrence.start != self.start or occurrence.end != self.end:
|
||||
occurrence.start = self.start
|
||||
occurrence.end = self.end
|
||||
occurrence.save(update_fields=["start", "end"])
|
||||
|
||||
self.occurrences.exclude(id=occurrence.id).delete()
|
||||
else:
|
||||
EventOccurrence.objects.create(
|
||||
event=self, start=self.start, end=self.end
|
||||
|
||||
214
home/signals.py
Normal file
214
home/signals.py
Normal file
@@ -0,0 +1,214 @@
|
||||
import logging as lg
|
||||
import os
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from home.models.pages import CoursePage, ModuleLessonPage
|
||||
|
||||
GITEA_ORG_NAME = "Studio77"
|
||||
|
||||
logger = lg.getLogger(__name__)
|
||||
|
||||
|
||||
@receiver(post_save, sender=CoursePage)
|
||||
def create_gitea_team_on_course_creation(sender, instance, created, **kwargs):
|
||||
if not instance.live:
|
||||
logger.debug(
|
||||
f"Course {instance.title} is not live, skipping Gitea team creation"
|
||||
)
|
||||
return
|
||||
|
||||
course = instance
|
||||
team_name = f"course-{course.id}"
|
||||
api_url = getattr(settings, "GITEA_URL", None)
|
||||
|
||||
if not api_url:
|
||||
logger.debug("GITEA_URL is not set, skipping Gitea team creation")
|
||||
return
|
||||
|
||||
# check if team already exists
|
||||
try:
|
||||
response = requests.get(
|
||||
f"{api_url}/orgs/{GITEA_ORG_NAME}/teams",
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
teams = response.json()
|
||||
if any(team["name"] == team_name for team in teams):
|
||||
logger.info(f"Gitea team {team_name} already exists, skipping creation")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Failed to check existing Gitea teams: {e}\n{response.text}",
|
||||
e,
|
||||
)
|
||||
return
|
||||
|
||||
url = f"{api_url}/orgs/{GITEA_ORG_NAME}/teams"
|
||||
payload = {
|
||||
"can_create_org_repo": False,
|
||||
"description": f"Team for course {course.title}",
|
||||
"includes_all_repositories": False,
|
||||
"name": team_name,
|
||||
"permission": "read",
|
||||
"units": [
|
||||
# "repo.actions",
|
||||
"repo.code",
|
||||
# "repo.issues",
|
||||
# "repo.ext_issues",
|
||||
# "repo.wiki",
|
||||
# "repo.ext_wiki",
|
||||
# "repo.pulls",
|
||||
# "repo.releases",
|
||||
# "repo.projects",
|
||||
# "repo.ext_wiki",
|
||||
],
|
||||
}
|
||||
try:
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
logger.info(
|
||||
f"Successfully created Gitea team `{team_name}` for course {course.title}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Failed to create Gitea team for course {course.title}: {e}\n{response.text}",
|
||||
e,
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_save, sender=ModuleLessonPage)
|
||||
def create_gitea_repo_on_lesson_creation(
|
||||
sender, instance: ModuleLessonPage, created, **kwargs
|
||||
):
|
||||
if not instance.live:
|
||||
logger.debug(
|
||||
f"Lesson {instance.title} is not live, skipping Gitea repository creation"
|
||||
)
|
||||
return
|
||||
|
||||
course = instance.module.course
|
||||
repo_name = f"course-{course.id}-lesson-{instance.id}"
|
||||
|
||||
if not instance.create_gitea_repo:
|
||||
logger.debug(
|
||||
f"Lesson {instance.title} is not marked for Gitea repository creation, skipping"
|
||||
)
|
||||
return
|
||||
|
||||
if not course.live:
|
||||
logger.debug(
|
||||
f"Course {course.title} is not live, skipping Gitea repository creation for lesson {instance.title}"
|
||||
)
|
||||
return
|
||||
|
||||
api_url = getattr(settings, "GITEA_URL", None)
|
||||
|
||||
if not api_url:
|
||||
logger.debug("GITEA_URL is not set, skipping Gitea repository creation")
|
||||
return
|
||||
|
||||
def create_repository() -> None:
|
||||
# check if repository already exists
|
||||
try:
|
||||
response = requests.get(
|
||||
f"{api_url}/orgs/{GITEA_ORG_NAME}/repos",
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
repos = response.json()
|
||||
if any(repo["name"] == repo_name for repo in repos):
|
||||
logger.info(
|
||||
f"Gitea repository {repo_name} already exists, skipping creation"
|
||||
)
|
||||
return
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Failed to check existing Gitea repositories: {e}\n{response.text}",
|
||||
e,
|
||||
)
|
||||
return
|
||||
|
||||
# create lesson repository
|
||||
url = f"{api_url}/orgs/{GITEA_ORG_NAME}/repos"
|
||||
payload = {
|
||||
"auto_init": True,
|
||||
"default_branch": "main",
|
||||
"description": f"{instance.module.course} – {instance.module}: {instance.title}",
|
||||
"name": repo_name,
|
||||
"private": True,
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
repo_url = response.json().get("html_url")
|
||||
|
||||
instance.gitea_repo_url = repo_url
|
||||
instance.save(update_fields=["gitea_repo_url"])
|
||||
|
||||
logger.info(
|
||||
f"Successfully created Gitea repository for lesson {instance.title}: {repo_url}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Failed to create Gitea repository for lesson {instance.title}: {e}\n{response.text}",
|
||||
e,
|
||||
)
|
||||
|
||||
def add_repository_to_team() -> None:
|
||||
# add repository to course team
|
||||
team_name = f"course-{course.id}"
|
||||
try:
|
||||
response = requests.get(
|
||||
f"{api_url}/orgs/{GITEA_ORG_NAME}/teams",
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
teams = response.json()
|
||||
|
||||
team = next((team for team in teams if team["name"] == team_name), None)
|
||||
|
||||
if not team:
|
||||
logger.error(
|
||||
f"Gitea team {team_name} not found when trying to add repository {repo_name}"
|
||||
)
|
||||
return
|
||||
|
||||
team_id = team["id"]
|
||||
add_repo_url = (
|
||||
f"{api_url}/teams/{team_id}/repos/{GITEA_ORG_NAME}/{repo_name}"
|
||||
)
|
||||
add_response = requests.put(
|
||||
add_repo_url,
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
add_response.raise_for_status()
|
||||
logger.info(
|
||||
f"Successfully added repository {repo_name} to Gitea team {team_name}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Failed to add repository {repo_name} to Gitea team {team_name}: {e}\n{response.text}",
|
||||
e,
|
||||
)
|
||||
|
||||
create_repository()
|
||||
add_repository_to_team()
|
||||
@@ -5,25 +5,88 @@
|
||||
{% trans "Chat with" %} {{ chat_user.email }}
|
||||
{% endblock titletag %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.admin-chat-messages {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 1.5em 0;
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e2e2e2;
|
||||
}
|
||||
.admin-chat-messages li {
|
||||
padding: 0.7em 1em;
|
||||
border-bottom: 1px solid #ececec;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
.admin-chat-messages li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.admin-chat-message-meta {
|
||||
color: #888;
|
||||
font-size: 0.92em;
|
||||
margin-right: 0.5em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.admin-chat-form {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.admin-chat-form input[type="text"] {
|
||||
flex: 1;
|
||||
padding: 0.5em;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 1em;
|
||||
}
|
||||
.admin-chat-form button {
|
||||
padding: 0.5em 1.2em;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
background: #0073e6;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.admin-chat-form button:hover {
|
||||
background: #005bb5;
|
||||
}
|
||||
.admin-message-admin {
|
||||
background: #334;
|
||||
}
|
||||
.admin-message-user {
|
||||
}
|
||||
</style>
|
||||
{% endblock extra_css %}
|
||||
|
||||
{% block content %}
|
||||
{% include "wagtailadmin/shared/header.html" with title="Chat" icon="mail" %}
|
||||
<h1>{% trans "Admin Chat View" %}</h1>
|
||||
<p>{% trans "This is the admin view of the chat. Here you can manage conversations and monitor user interactions." %}</p>
|
||||
<div style="padding: 0 3em;">
|
||||
<a href="{% url 'user_chat' %}" class="button button-secondary">← {% trans "Back" %}</a>
|
||||
<h1>{% trans "Chat with" %} <em>{{ chat_user.email }}</em></h1>
|
||||
|
||||
<ul>
|
||||
{% for message in chat_messages %}
|
||||
<li>
|
||||
<strong>{{ message.sender.email }}:</strong> {{ message.content }}
|
||||
</li>
|
||||
{% empty %}
|
||||
<li>{% trans "No messages found." %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<form action="/chat/send/{{ chat_user.id }}/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="text" name="content" placeholder="{% trans "Type your message here..." %}" required>
|
||||
<button type="submit">{% trans "Send" %}</button>
|
||||
</form>
|
||||
<ul class="admin-chat-messages">
|
||||
{% for message in chat_messages %}
|
||||
<li class="{% if message.sender.id == chat_user.id %}admin-message-user{% else %}admin-message-admin{% endif %}">
|
||||
<span class="admin-chat-message-meta">{{ message.timestamp|date:"Y-m-d H:i" }}</span>
|
||||
<strong>{{ message.sender.email }}: </strong> {{ message.content }}
|
||||
</li>
|
||||
{% empty %}
|
||||
<li>{% trans "No messages found." %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<form action="/chat/send/{{ chat_user.id }}/" method="post" class="admin-chat-form">
|
||||
{% csrf_token %}
|
||||
<input type="text" name="content" placeholder="{% trans "Type your message here..." %}" required>
|
||||
<button type="submit">{% trans "Send" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
|
||||
|
||||
@@ -6,21 +6,36 @@
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% trans "Chat with Support" %}</h1>
|
||||
<p>{% trans "This is the user chat interface. Here you can communicate with our support team for assistance." %}</p>
|
||||
<h1 class="text-2xl font-bold mb-4 text-gray-800">{% trans "Chat with Support" %}</h1>
|
||||
<p class="mb-6 text-gray-600">{% trans "Welcome! We're here to help. Type your message below to start a conversation with our support team." %}</p>
|
||||
|
||||
<ul>
|
||||
{% for message in chat_messages %}
|
||||
<li>
|
||||
<strong>{{ message.sender.email }}:</strong> {{ message.content }}
|
||||
<ul class="flex flex-col gap-2 mb-6">
|
||||
{% regroup chat_messages by timestamp.date as dated_messages %}
|
||||
{% for day in dated_messages %}
|
||||
<li class="flex justify-center my-2">
|
||||
<span class="px-4 py-1 bg-gray-100 text-gray-500 text-xs rounded-full shadow">{{ day.grouper|date:'l, d M Y' }}</span>
|
||||
</li>
|
||||
{% for message in day.list %}
|
||||
<li class="flex flex-col items-start {% if message.sender.id == user.id %}items-end{% endif %}">
|
||||
<div class="max-w-xs px-4 py-2 rounded-2xl shadow text-sm
|
||||
{% if message.sender.id == user.id %}
|
||||
bg-blue-600 text-white rounded-br-none self-end
|
||||
{% else %}
|
||||
bg-gray-200 text-gray-900 rounded-bl-none self-start
|
||||
{% endif %}">
|
||||
<span class="block font-semibold text-xs mb-1 {% if message.sender.id == user.id %}text-blue-100{% else %}text-blue-700{% endif %}">{{ message.sender.email }}</span>
|
||||
<span>{{ message.content }}</span>
|
||||
<span class="block text-xs {% if message.sender.id == user.id %}text-blue-100{% else %}text-blue-700{% endif %} mt-1 text-right">{{ message.timestamp|date:'H:i' }}</span>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% empty %}
|
||||
<li>{% trans "No messages found." %}</li>
|
||||
<li class="text-gray-400">{% trans "No messages found." %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<form action="/chat/send/{{ user.id }}/" method="post">
|
||||
<form action="/chat/send/{{ user.id }}/" method="post" class="flex gap-4">
|
||||
{% csrf_token %}
|
||||
<textarea name="content" placeholder="{% trans "Type your message here..." %}"></textarea>
|
||||
<button type="submit">{% trans "Send" %}</button>
|
||||
<textarea rows=1 name="content" placeholder="{% trans "Type your message here..." %}" class="grow resize-y min-h-10 border border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-gray-800"></textarea>
|
||||
<button type="submit" class="self-center px-5 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition">{% trans "Send" %}</button>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
36
home/templates/home/blog_index_page.html
Normal file
36
home/templates/home/blog_index_page.html
Normal file
@@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static i18n wagtailcore_tags wagtailimages_tags %}
|
||||
|
||||
{% block title %}{% trans "Blog" %}{% endblock title %}
|
||||
|
||||
{% block body_class %}template-blogindex{% endblock body_class %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="text-3xl font-bold mb-6 text-gray-800 text-center">
|
||||
{% trans "Blog" %}
|
||||
</h1>
|
||||
|
||||
<div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{% for post in posts %}
|
||||
<a href="{{ post.url }}" class="block bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
|
||||
{% image post.specific.image original %}
|
||||
<div class="p-4">
|
||||
<div class="flex justify-between items-center mb-2 text-gray-500">
|
||||
<div class="flex items-center gap-1">
|
||||
<i class="fi fi-br-circle-user leading-0"></i>
|
||||
<span class="text-sm">{{ post.specific.author }}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<i class="fi fi-br-calendar leading-0"></i>
|
||||
<span class="text-sm">{{ post.first_published_at|date:"F j, Y | H:i" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold mb-2">{{ post.specific.title }}</h2>
|
||||
<p class="text-gray-600">{{ post.specific.description|truncatewords:20 }}</p>
|
||||
</div>
|
||||
</a>
|
||||
{% empty %}
|
||||
<p class="text-gray-600">{% trans "No blog posts available." %}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
45
home/templates/home/blog_page.html
Normal file
45
home/templates/home/blog_page.html
Normal file
@@ -0,0 +1,45 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static i18n wagtailcore_tags wagtailimages_tags %}
|
||||
|
||||
{% block title %}{{ page.specific.title }} | {% trans "Blog" %}{% endblock title %}
|
||||
|
||||
{% block body_class %}template-blog{% endblock body_class %}
|
||||
|
||||
{% block content %}
|
||||
<div class="max-w-3xl mx-auto py-12 px-4">
|
||||
<a href="{{ page.get_parent.url }}" class="inline-flex items-center gap-1 text-gray-500 text-4xl mb-4 hover:text-gray-700 transition-colors duration-300">
|
||||
<i class="fi fi-br-arrow-left leading-0"></i>
|
||||
</a>
|
||||
<h1 class="text-4xl font-bold mb-6 text-gray-800">
|
||||
{{ page.specific.title }}
|
||||
</h1>
|
||||
<div class="flex items-center gap-4 mb-8 text-gray-500">
|
||||
<div class="flex items-center gap-1">
|
||||
<i class="fi fi-br-circle-user leading-0"></i>
|
||||
<span class="text-sm">{{ page.specific.author }}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<i class="fi fi-br-calendar leading-0"></i>
|
||||
<span class="text-sm">{{ page.first_published_at|date:"F j, Y | H:i" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if page.specific.image %}
|
||||
<div class="mb-8">
|
||||
{% image page.specific.image original class="w-full max-h-100 object-contain rounded-lg" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<article class="prose max-w-none">
|
||||
{% for block in page.body %}
|
||||
{% if block.block_type == 'heading' %}
|
||||
<h2>
|
||||
{{ block.value }}
|
||||
</h2>
|
||||
{% else %}
|
||||
<section class="block-{{ block.block_type }}">
|
||||
{% include_block block %}
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</article>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
52
home/templates/home/course_index_page.html
Normal file
52
home/templates/home/course_index_page.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static i18n wagtailcore_tags wagtailimages_tags %}
|
||||
|
||||
{% block title %}{% trans "Courses" %}{% endblock title %}
|
||||
|
||||
{% block body_class %}template-courseindex{% endblock body_class %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1 class="text-3xl font-bold mb-6 text-center">{% trans "Courses" %}</h1>
|
||||
|
||||
<h2 class="text-2xl font-semibold mb-4">{% trans "Purchased Courses" %}</h2>
|
||||
<div class="flex flex-wrap -mx-4">
|
||||
{% for course in purchased_courses %}
|
||||
<div class="w-full md:w-1/2 lg:w-1/3 px-4 mb-8">
|
||||
<a href="{{ course.url }}" class="block bg-green-50 rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
|
||||
{% image course.specific.course_image original %}
|
||||
<div class="p-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h2 class="text-xl font-semibold">{{ course.specific.title }}</h2>
|
||||
<div class="relative w-8 h-8 rounded-full bg-green-500">
|
||||
<i class="fi fi-br-lock-open-alt leading-0 absolute left-0 top-1/2 translate-x-1/2 -translate-y-1/2 text-white" title="{% trans "Purchased" %}"></i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-gray-600">{{ course.specific.description|truncatewords:20 }}</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h2 class="text-2xl font-semibold mb-4">{% trans "Available Courses" %}</h2>
|
||||
<div class="flex flex-wrap -mx-4">
|
||||
{% for course in other_courses %}
|
||||
<div class="w-full md:w-1/2 lg:w-1/3 px-4 mb-8">
|
||||
<a href="{{ course.url }}" class="block bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
|
||||
{% image course.specific.course_image original %}
|
||||
<div class="p-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h2 class="text-xl font-semibold">{{ course.specific.title }}</h2>
|
||||
<div class="relative w-8 h-8 rounded-full bg-gray-200">
|
||||
<i class="fi fi-br-shopping-basket leading-0 absolute left-0 top-1/2 translate-x-1/2 -translate-y-1/2 text-gray-700" title="{% trans "Not Purchased" %}"></i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-gray-600">{{ course.specific.description|truncatewords:20 }}</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
@@ -13,7 +13,9 @@
|
||||
|
||||
{% block content %}
|
||||
<h2 class="not-prose text-xl mb-4 text-gray-700">
|
||||
<a href="{{ page.course.url }}" class="font-bold">{{ page.course.title }}</a> » {{ page.title }}
|
||||
<a href="{% slugurl 'courses' %}" class="font-bold hover:underline">{% trans "Courses" %}</a>
|
||||
» <a href="{{ page.course.url }}" class="font-bold hover:underline">{{ page.course.title }}</a>
|
||||
» {{ page.title }}
|
||||
</h2>
|
||||
|
||||
{{ page.body|richtext }}
|
||||
|
||||
@@ -12,17 +12,25 @@
|
||||
{% block content_class %}prose{% endblock content_class %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="not-prose text-3xl mb-4 text-gray-700 font-bold">
|
||||
{{ page.title }}
|
||||
<h1 class="not-prose text-3xl mb-4 text-gray-700">
|
||||
<a href="{% slugurl 'courses' %}" class="font-bold hover:underline">{% trans "Courses" %}</a>
|
||||
» {{ page.title }}
|
||||
</h1>
|
||||
|
||||
{% if page.course_image %}
|
||||
{% image page.course_image original alt=page.title class="w-full h-auto rounded-lg mb-6" %}
|
||||
{% image page.course_image original alt=page.title class="w-full h-auto rounded-lg mb-4" %}
|
||||
{% endif %}
|
||||
|
||||
<p class="not-prose text-gray-600 mb-6 text-lg">
|
||||
{{ page.description }}
|
||||
</p>
|
||||
|
||||
{{ page.body|richtext }}
|
||||
|
||||
{% if user_has_access %}
|
||||
{% if user_purchase_id %}
|
||||
<a href="{% url 'mock_refund_purchase' purchase_id=user_purchase_id %}" class="mt-4 inline-block bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition">{% trans "Refund Purchase" %}</a>
|
||||
{% endif %}
|
||||
<h2 class="not-prose text-2xl mt-8 mb-4 text-gray-700 font-semibold">{% trans "Modules" %}</h2>
|
||||
<ul class="list-disc list-inside">
|
||||
{% for module in page.get_children.specific.live %}
|
||||
@@ -44,7 +52,7 @@
|
||||
{% else %}
|
||||
<div class="not-prose mt-8 p-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700">
|
||||
<p>{% trans "You don't have access to this course. Please purchase it to view the modules." %}</p>
|
||||
<a href="" class="mt-4 inline-block bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition">{% trans "Purchase Course" %}</a>
|
||||
<a href="{% url 'mock_purchase_course' course_id=page.id %}" class="mt-4 inline-block bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition">{% trans "Purchase Course" %}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
|
||||
@@ -13,13 +13,21 @@
|
||||
|
||||
{% block content %}
|
||||
<h2 class="not-prose text-xl mb-4 text-gray-700">
|
||||
<a href="{{ page.module.course.url }}" class="font-bold">{{ page.module.course.title }}</a>
|
||||
»
|
||||
<a href="{{ page.module.url }}" class="font-bold">{{ page.module.title }}</a>
|
||||
»
|
||||
<span class="text-gray-500">{{ page.title }}</span>
|
||||
<a href="{% slugurl 'courses' %}" class="font-bold hover:underline">{% trans "Courses" %}</a>
|
||||
» <a href="{{ page.module.course.url }}" class="font-bold hover:underline">{{ page.module.course.title }}</a>
|
||||
» <a href="{{ page.module.url }}" class="font-bold hover:underline">{{ page.module.title }}</a>
|
||||
» <span class="text-gray-500">{{ page.title }}</span>
|
||||
</h2>
|
||||
|
||||
{% if page.create_gitea_repo and page.gitea_repo_url %}
|
||||
<p class="not-prose mb-6 text-gray-600 text-lg flex items-center gap-1">
|
||||
<i class="fi fi-br-code-window leading-0"></i>
|
||||
<a href="{{ page.gitea_login_redirect_url }}" class="hover:underline" target="_blank" rel="noopener noreferrer">
|
||||
{% trans "View code on Gitea" %}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{{ page.body|richtext }}
|
||||
{% endblock content %}
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
{% load i18n wagtailcore_tags %}
|
||||
|
||||
<header class="header">
|
||||
<div class="logo">
|
||||
<a href="https://wagtail.org/">
|
||||
<svg class="figure-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 342.5 126.2"><title>{% trans "Visit the Wagtail website" %}</title><path fill="#FFF" d="M84 1.9v5.7s-10.2-3.8-16.8 3.1c-4.8 5-5.2 10.6-3 18.1 21.6 0 25 12.1 25 12.1L87 27l6.8-8.3c0-9.8-8.1-16.3-9.8-16.8z"/><circle cx="85.9" cy="15.9" r="2.6"/><path d="M89.2 40.9s-3.3-16.6-24.9-12.1c-2.2-7.5-1.8-13 3-18.1C73.8 3.8 84 7.6 84 7.6V1.9C80.4.3 77 0 73.2 0 59.3 0 51.6 10.4 48.3 17.4L9.2 89.3l11-2.1-20.2 39 14.1-2.5L24.9 93c30.6 0 69.8-11 64.3-52.1z"/><path d="M102.4 27l-8.6-8.3L87 27z"/><path fill="#FFF" d="M30 84.1s1-.2 2.8-.6c1.8-.4 4.3-1 7.3-1.8 1.5-.4 3.1-.9 4.8-1.5 1.7-.6 3.5-1.2 5.2-2 1.8-.7 3.6-1.6 5.4-2.6 1.8-1 3.5-2.1 5.1-3.4.4-.3.8-.6 1.2-1l1.2-1c.7-.7 1.5-1.4 2.2-2.2.7-.7 1.3-1.5 1.9-2.3l.9-1.2.4-.6.4-.6c.2-.4.5-.8.7-1.2.2-.4.4-.8.7-1.2l.3-.6.3-.6c.2-.4.4-.8.5-1.2l.9-2.4c.2-.8.5-1.6.7-2.3.2-.7.3-1.5.5-2.1.1-.7.2-1.3.3-2 .1-.6.2-1.2.2-1.7.1-.5.1-1 .2-1.5.1-1.8.1-2.8.1-2.8l1.6.1s-.1 1.1-.2 2.9c-.1.5-.1 1-.2 1.5-.1.6-.1 1.2-.3 1.8-.1.6-.3 1.3-.4 2-.2.7-.4 1.4-.6 2.2-.2.8-.5 1.5-.8 2.4-.3.8-.6 1.6-1 2.5l-.6 1.2-.3.6-.3.6c-.2.4-.5.8-.7 1.3-.3.4-.5.8-.8 1.2-.1.2-.3.4-.4.6l-.4.6-.9 1.2c-.7.8-1.3 1.6-2.1 2.3-.7.8-1.5 1.4-2.3 2.2l-1.2 1c-.4.3-.8.6-1.3.9-1.7 1.2-3.5 2.3-5.3 3.3-1.8.9-3.7 1.8-5.5 2.5-1.8.7-3.6 1.3-5.3 1.8-1.7.5-3.3 1-4.9 1.3-3 .7-5.6 1.3-7.4 1.6-1.6.6-2.6.8-2.6.8z"/><g fill="#231F20"><path d="M127 83.9h-8.8l-12.6-36.4h7.9l9 27.5 9-27.5h7.9l9 27.5 9-27.5h7.9L153 83.9h-8.8L135.6 59 127 83.9zM200.1 83.9h-7V79c-3 3.6-7 5.4-12.1 5.4-3.8 0-6.9-1.1-9.4-3.2s-3.7-5-3.7-8.6c0-3.6 1.3-6.3 4-8 2.6-1.8 6.2-2.7 10.7-2.7h9.9v-1.4c0-4.8-2.7-7.3-8.1-7.3-3.4 0-6.9 1.2-10.5 3.7l-3.4-4.8c4.4-3.5 9.4-5.3 15.1-5.3 4.3 0 7.8 1.1 10.5 3.2 2.7 2.2 4.1 5.6 4.1 10.2v23.7zm-7.7-13.6v-3.1h-8.6c-5.5 0-8.3 1.7-8.3 5.2 0 1.8.7 3.1 2.1 4.1 1.4.9 3.3 1.4 5.7 1.4 2.4 0 4.6-.7 6.4-2.1 1.8-1.3 2.7-3.1 2.7-5.5zM241.7 47.5v31.7c0 6.4-1.7 11.3-5.2 14.5-3.5 3.2-8 4.8-13.4 4.8-5.5 0-10.4-1.7-14.8-5.1l3.6-5.8c3.6 2.7 7.1 4 10.8 4 3.6 0 6.5-.9 8.6-2.8 2.1-1.9 3.2-4.9 3.2-9v-4.7c-1.1 2.1-2.8 3.9-4.9 5.1-2.1 1.3-4.5 1.9-7.1 1.9-4.8 0-8.8-1.7-11.9-5.1-3.1-3.4-4.7-7.6-4.7-12.6s1.6-9.2 4.7-12.6c3.1-3.4 7.1-5.1 11.9-5.1 4.8 0 8.7 2 11.7 6v-5.4h7.5zm-28.4 16.8c0 3 .9 5.6 2.8 7.7 1.8 2.2 4.3 3.2 7.5 3.2 3.1 0 5.7-1 7.6-3.1 1.9-2.1 2.9-4.7 2.9-7.8 0-3.1-1-5.8-2.9-7.9-2-2.2-4.5-3.2-7.6-3.2-3.1 0-5.6 1.1-7.4 3.4-2 2.1-2.9 4.7-2.9 7.7zM260.9 53.6v18.5c0 1.7.5 3.1 1.4 4.1.9 1 2.2 1.5 3.8 1.5 1.6 0 3.2-.8 4.7-2.4l3.1 5.4c-2.7 2.4-5.7 3.6-8.9 3.6-3.3 0-6-1.1-8.3-3.4-2.3-2.3-3.5-5.3-3.5-9.1V53.6h-4.6v-6.2h4.6V36.1h7.7v11.4h9.6v6.2h-9.6zM309.5 83.9h-7V79c-3 3.6-7 5.4-12.1 5.4-3.8 0-6.9-1.1-9.4-3.2s-3.7-5-3.7-8.6c0-3.6 1.3-6.3 4-8 2.6-1.8 6.2-2.7 10.7-2.7h9.9v-1.4c0-4.8-2.7-7.3-8.1-7.3-3.4 0-6.9 1.2-10.5 3.7l-3.4-4.8c4.4-3.5 9.4-5.3 15.1-5.3 4.3 0 7.8 1.1 10.5 3.2 2.7 2.2 4.1 5.6 4.1 10.2v23.7zm-7.7-13.6v-3.1h-8.6c-5.5 0-8.3 1.7-8.3 5.2 0 1.8.7 3.1 2.1 4.1 1.4.9 3.3 1.4 5.7 1.4 2.4 0 4.6-.7 6.4-2.1 1.8-1.3 2.7-3.1 2.7-5.5zM319.3 40.2c-1-1-1.4-2.1-1.4-3.4 0-1.3.5-2.5 1.4-3.4 1-1 2.1-1.4 3.4-1.4 1.3 0 2.5.5 3.4 1.4 1 1 1.4 2.1 1.4 3.4 0 1.3-.5 2.5-1.4 3.4s-2.1 1.4-3.4 1.4c-1.3.1-2.4-.4-3.4-1.4zm7.2 43.7h-7.7V47.5h7.7v36.4zM342.5 83.9h-7.7V33.1h7.7v50.8z"/></g></svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="header-link">
|
||||
{% comment %}
|
||||
This works for all cases but prerelease versions:
|
||||
{% endcomment %}
|
||||
<a href="{% wagtail_documentation_path %}/releases/{% wagtail_release_notes_path %}">
|
||||
{% trans "View the release notes" %}
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<main class="main">
|
||||
<div class="figure">
|
||||
<svg class="figure-space" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300" aria-hidden="true">
|
||||
<path class="egg" fill="currentColor" d="M150 250c-42.741 0-75-32.693-75-90s42.913-110 75-110c32.088 0 75 52.693 75 110s-32.258 90-75 90z"/>
|
||||
<ellipse fill="#ddd" cx="150" cy="270" rx="40" ry="7"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="main-text">
|
||||
<h1>{% trans "Welcome to your new Wagtail site!" %}</h1>
|
||||
<p>{% trans 'Please feel free to <a href="https://github.com/wagtail/wagtail/wiki/Slack">join our community on Slack</a>, or get started with one of the links below.' %}</p>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="footer" role="contentinfo">
|
||||
<a class="option option-one" href="{% wagtail_documentation_path %}/">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 21c0 .5.4 1 1 1h4c.6 0 1-.5 1-1v-1H9v1zm3-19C8.1 2 5 5.1 5 9c0 2.4 1.2 4.5 3 5.7V17c0 .5.4 1 1 1h6c.6 0 1-.5 1-1v-2.3c1.8-1.3 3-3.4 3-5.7 0-3.9-3.1-7-7-7zm2.9 11.1l-.9.6V16h-4v-2.3l-.9-.6C7.8 12.2 7 10.6 7 9c0-2.8 2.2-5 5-5s5 2.2 5 5c0 1.6-.8 3.2-2.1 4.1z"/></svg>
|
||||
<div>
|
||||
<h2>{% trans "Wagtail Documentation" %}</h2>
|
||||
<p>{% trans "Topics, references, & how-tos" %}</p>
|
||||
</div>
|
||||
</a>
|
||||
<a class="option option-two" href="{% wagtail_documentation_path %}/getting_started/tutorial.html">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></svg>
|
||||
<div>
|
||||
<h2>{% trans "Tutorial" %}</h2>
|
||||
<p>{% trans "Build your first Wagtail site" %}</p>
|
||||
</div>
|
||||
</a>
|
||||
<a class="option option-three" href="{% url 'wagtailadmin_home' %}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"/><path d="M16.5 13c-1.2 0-3.07.34-4.5 1-1.43-.67-3.3-1-4.5-1C5.33 13 1 14.08 1 16.25V19h22v-2.75c0-2.17-4.33-3.25-6.5-3.25zm-4 4.5h-10v-1.25c0-.54 2.56-1.75 5-1.75s5 1.21 5 1.75v1.25zm9 0H14v-1.25c0-.46-.2-.86-.52-1.22.88-.3 1.96-.53 3.02-.53 2.44 0 5 1.21 5 1.75v1.25zM7.5 12c1.93 0 3.5-1.57 3.5-3.5S9.43 5 7.5 5 4 6.57 4 8.5 5.57 12 7.5 12zm0-5.5c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 5.5c1.93 0 3.5-1.57 3.5-3.5S18.43 5 16.5 5 13 6.57 13 8.5s1.57 3.5 3.5 3.5zm0-5.5c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2z"/></svg>
|
||||
<div>
|
||||
<h2>{% trans "Admin Interface" %}</h2>
|
||||
<p>{% trans "Create your superuser first!" %}</p>
|
||||
</div>
|
||||
</a>
|
||||
</footer>
|
||||
@@ -14,7 +14,6 @@ def admin_chat_dashboard(request):
|
||||
@login_required
|
||||
def admin_chat(request, user_id):
|
||||
chat_user = User.objects.filter(id=user_id, is_staff=False).first()
|
||||
print(chat_user)
|
||||
chat_messages = ChatMessage.get_support_chat(chat_user)
|
||||
return render(
|
||||
request,
|
||||
|
||||
@@ -1,13 +1,63 @@
|
||||
import logging as lg
|
||||
import os
|
||||
|
||||
import requests
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
|
||||
logger = lg.getLogger(__name__)
|
||||
|
||||
|
||||
def create_gitea_account(user, password):
|
||||
payload = {
|
||||
"user_id": user.id,
|
||||
"username": f"studio77-{user.id}",
|
||||
"email": user.email,
|
||||
"full_name": f"{user.first_name} {user.last_name}".strip(),
|
||||
"password": password,
|
||||
"must_change_password": False,
|
||||
"visibility": "private",
|
||||
}
|
||||
api_url = getattr(settings, "GITEA_URL", None)
|
||||
if api_url:
|
||||
url = f"{api_url}/admin/users"
|
||||
try:
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
logger.info(f"Successfully created Gitea account for {user.email}")
|
||||
except requests.exceptions.HTTPError as http_err:
|
||||
status_code = http_err.response.status_code
|
||||
if status_code == 422:
|
||||
logger.warning(
|
||||
f"Gitea account for user {user.email} already exists. Skipping creation."
|
||||
)
|
||||
else:
|
||||
logger.error(
|
||||
f"HTTP error occurred while creating Gitea account for user {user.email}: {http_err}\n{response.text}"
|
||||
)
|
||||
raise http_err
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Failed to create Gitea account for user {user.email}: {e}\n{response.text}"
|
||||
)
|
||||
raise e
|
||||
|
||||
|
||||
class SignUpForm(forms.Form):
|
||||
first_name = forms.CharField(max_length=60, required=True, label="First Name")
|
||||
last_name = forms.CharField(max_length=60, required=True, label="Last Name")
|
||||
|
||||
def signup(self, request, user):
|
||||
user.first_name = self.cleaned_data["first_name"]
|
||||
user.last_name = self.cleaned_data["last_name"]
|
||||
def signup(self, request: WSGIRequest, user):
|
||||
user.first_name = self.cleaned_data["first_name"].strip().title()
|
||||
user.last_name = self.cleaned_data["last_name"].strip().title()
|
||||
user.save()
|
||||
|
||||
return user
|
||||
# gitea account creation
|
||||
password = request.POST.get("password1")
|
||||
create_gitea_account(user, password)
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-17 11:46+0000\n"
|
||||
"POT-Creation-Date: 2026-03-20 12:18+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -26,7 +26,7 @@ msgstr ""
|
||||
msgid "Sorry, you don't have permission to access this page."
|
||||
msgstr ""
|
||||
|
||||
#: kursy/templates/calendar.html:4 kursy/templates/header.html:8
|
||||
#: kursy/templates/calendar.html:4
|
||||
msgid "Course Calendar"
|
||||
msgstr ""
|
||||
|
||||
@@ -34,19 +34,27 @@ msgstr ""
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
#: kursy/templates/header.html:10
|
||||
#: kursy/templates/header.html:7
|
||||
msgid "Courses"
|
||||
msgstr ""
|
||||
|
||||
#: kursy/templates/header.html:8
|
||||
msgid "Calendar"
|
||||
msgstr ""
|
||||
|
||||
#: kursy/templates/header.html:13
|
||||
msgid "Logout"
|
||||
msgstr ""
|
||||
|
||||
#: kursy/templates/header.html:12 kursy/templates/occurrence_detail.html:39
|
||||
#: kursy/templates/header.html:15 kursy/templates/occurrence_detail.html:39
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: kursy/templates/header.html:13 kursy/templates/occurrence_detail.html:42
|
||||
#: kursy/templates/header.html:16 kursy/templates/occurrence_detail.html:42
|
||||
msgid "Sign Up"
|
||||
msgstr ""
|
||||
|
||||
#: kursy/templates/header.html:32
|
||||
#: kursy/templates/header.html:35
|
||||
msgid "Search courses..."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-17 11:46+0000\n"
|
||||
"POT-Creation-Date: 2026-03-20 12:18+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -28,7 +28,7 @@ msgstr "Odmowa dostępu"
|
||||
msgid "Sorry, you don't have permission to access this page."
|
||||
msgstr "Przepraszamy, ale nie masz uprawnień do dostępu do tej strony."
|
||||
|
||||
#: kursy/templates/calendar.html:4 kursy/templates/header.html:8
|
||||
#: kursy/templates/calendar.html:4
|
||||
msgid "Course Calendar"
|
||||
msgstr "Kalendarz kursów"
|
||||
|
||||
@@ -36,19 +36,27 @@ msgstr "Kalendarz kursów"
|
||||
msgid "Loading..."
|
||||
msgstr "Ładowanie..."
|
||||
|
||||
#: kursy/templates/header.html:10
|
||||
#: kursy/templates/header.html:7
|
||||
msgid "Courses"
|
||||
msgstr "Kursy"
|
||||
|
||||
#: kursy/templates/header.html:8
|
||||
msgid "Calendar"
|
||||
msgstr "Kalendarz"
|
||||
|
||||
#: kursy/templates/header.html:13
|
||||
msgid "Logout"
|
||||
msgstr "Wyloguj się"
|
||||
|
||||
#: kursy/templates/header.html:12 kursy/templates/occurrence_detail.html:39
|
||||
#: kursy/templates/header.html:15 kursy/templates/occurrence_detail.html:39
|
||||
msgid "Login"
|
||||
msgstr "Zaloguj się"
|
||||
|
||||
#: kursy/templates/header.html:13 kursy/templates/occurrence_detail.html:42
|
||||
#: kursy/templates/header.html:16 kursy/templates/occurrence_detail.html:42
|
||||
msgid "Sign Up"
|
||||
msgstr "Zarejestruj się"
|
||||
|
||||
#: kursy/templates/header.html:32
|
||||
#: kursy/templates/header.html:35
|
||||
msgid "Search courses..."
|
||||
msgstr "Szukaj kursów..."
|
||||
|
||||
@@ -62,8 +70,6 @@ msgid "You are signed up for this event. We look forward to seeing you there!"
|
||||
msgstr ""
|
||||
|
||||
#: kursy/templates/occurrence_detail.html:31
|
||||
#, fuzzy
|
||||
#| msgid "Sign Up"
|
||||
msgid "Cancel Sign Up"
|
||||
msgstr "Zrezygnuj"
|
||||
|
||||
@@ -71,17 +77,23 @@ msgstr "Zrezygnuj"
|
||||
msgid ""
|
||||
"You need to be logged in to sign up for this event. Please log in or sign up "
|
||||
"to reserve your spot."
|
||||
msgstr "Musisz być zalogowany, aby zapisać się na to wydarzenie. Zaloguj się lub zarejestruj, aby zarezerwować swoje miejsce."
|
||||
msgstr ""
|
||||
"Musisz być zalogowany, aby zapisać się na to wydarzenie. Zaloguj się lub "
|
||||
"zarejestruj, aby zarezerwować swoje miejsce."
|
||||
|
||||
#: kursy/templates/occurrence_detail.html:47
|
||||
msgid ""
|
||||
"This event is fully booked. Please check back later for any cancellations."
|
||||
msgstr "To wydarzenie jest w pełni zarezerwowane. Sprawdź ponownie później w przypadku zwolnienia miejsc."
|
||||
msgstr ""
|
||||
"To wydarzenie jest w pełni zarezerwowane. Sprawdź ponownie później w "
|
||||
"przypadku zwolnienia miejsc."
|
||||
|
||||
#: kursy/templates/occurrence_detail.html:51
|
||||
msgid ""
|
||||
"You are not signed up for this event. Please sign up to reserve your spot."
|
||||
msgstr "Nie jesteś zapisany na to wydarzenie. Zapisz się, aby zarezerwować swoje miejsce."
|
||||
msgstr ""
|
||||
"Nie jesteś zapisany na to wydarzenie. Zapisz się, aby zarezerwować swoje "
|
||||
"miejsce."
|
||||
|
||||
#: kursy/templates/occurrence_detail.html:53
|
||||
msgid "Sign Up for Event"
|
||||
|
||||
11
kursy/oauth_validators.py
Normal file
11
kursy/oauth_validators.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from oauth2_provider.oauth2_validators import OAuth2Validator
|
||||
|
||||
|
||||
class CustomOAuth2Validator(OAuth2Validator):
|
||||
def get_additional_claims(self, request):
|
||||
print("get_additional_claims", request.user)
|
||||
return {
|
||||
"name": " ".join([request.user.first_name, request.user.last_name]),
|
||||
"preferred_username": f"studio77-{request.user.id}",
|
||||
"email": request.user.email,
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import os
|
||||
from pathlib import Path
|
||||
|
||||
import dotenv
|
||||
import logging as lg
|
||||
|
||||
PROJECT_DIR = Path(__file__).resolve().parent.parent
|
||||
BASE_DIR = PROJECT_DIR.parent
|
||||
@@ -32,6 +33,7 @@ dotenv.load_dotenv(BASE_DIR / ".env")
|
||||
INSTALLED_APPS = [
|
||||
"home",
|
||||
"search",
|
||||
"purchase",
|
||||
"wagtail.contrib.forms",
|
||||
"wagtail.contrib.redirects",
|
||||
"wagtail.embeds",
|
||||
@@ -58,6 +60,7 @@ INSTALLED_APPS = [
|
||||
"allauth.account",
|
||||
"allauth.socialaccount",
|
||||
"allauth.socialaccount.providers.github",
|
||||
"oauth2_provider",
|
||||
"tailwind",
|
||||
"theme",
|
||||
"widget_tweaks",
|
||||
@@ -75,6 +78,7 @@ MIDDLEWARE = [
|
||||
"wagtail.contrib.redirects.middleware.RedirectMiddleware",
|
||||
"allauth.account.middleware.AccountMiddleware",
|
||||
"django.middleware.locale.LocaleMiddleware",
|
||||
"oauth2_provider.middleware.OAuth2TokenMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "kursy.urls"
|
||||
@@ -131,6 +135,26 @@ SOCIALACCOUNT_PROVIDERS = {
|
||||
|
||||
WSGI_APPLICATION = "kursy.wsgi.application"
|
||||
|
||||
OAUTH2_PROVIDER = {
|
||||
"OIDC_ENABLED": True,
|
||||
"OIDC_RPID_ENDPOINT": "http://127.0.0.1:8000/oauth2",
|
||||
"OIDC_ISS_ENDPOINT": "http://127.0.0.1:8000",
|
||||
"PKCE_REQUIRED": False,
|
||||
"OAUTH2_VALIDATOR_CLASS": "kursy.oauth_validators.CustomOAuth2Validator",
|
||||
"SCOPES": {
|
||||
"openid": "OpenID Connect scope",
|
||||
"profile": "User profile scope",
|
||||
"email": "User email scope",
|
||||
"read": "Read scope",
|
||||
"write": "Write scope",
|
||||
},
|
||||
"OIDC_CLAIM_MAPS": {
|
||||
"nickname": "preferred_username",
|
||||
"email": "email",
|
||||
},
|
||||
"DEFAULT_SCOPES": ["openid", "profile", "email"],
|
||||
}
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
|
||||
@@ -138,7 +162,7 @@ WSGI_APPLICATION = "kursy.wsgi.application"
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
"NAME": BASE_DIR / "db" / "db.sqlite3",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +242,43 @@ STORAGES = {
|
||||
DATA_UPLOAD_MAX_NUMBER_FIELDS = 10_000
|
||||
|
||||
|
||||
# Logging
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"verbose": {
|
||||
"format": "{asctime} : {levelname} : {filename}:{lineno} : {name} :: {message}",
|
||||
"style": "{",
|
||||
},
|
||||
"simple": {"format": "{asctime} : {levelname} :: {message}", "style": "{"},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "verbose",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"django": {
|
||||
"handlers": ["console"],
|
||||
"level": "INFO",
|
||||
"propagate": True,
|
||||
},
|
||||
"django.request": {
|
||||
"handlers": ["console"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
"home": {
|
||||
"handlers": ["console"],
|
||||
"level": "DEBUG",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# Wagtail settings
|
||||
|
||||
WAGTAIL_SITE_NAME = "kursy"
|
||||
@@ -252,3 +313,12 @@ WAGTAILDOCS_EXTENSIONS = [
|
||||
]
|
||||
|
||||
TAILWIND_APP_NAME = "theme"
|
||||
|
||||
# Gitea API
|
||||
GITEA_ROOT_URL = "http://localhost:3000"
|
||||
GITEA_URL = f"{GITEA_ROOT_URL}/api/v1"
|
||||
|
||||
lg.basicConfig(
|
||||
level=lg.DEBUG,
|
||||
format="%(asctime)s : %(levelname)s : %(filename)s:%(lineno)d : %(name)s :: %(message)s",
|
||||
)
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
{% load i18n wagtailcore_tags %}
|
||||
<header class="bg-blue-900 text-white shadow-md relative">
|
||||
<header class="bg-blue-900 text-white shadow-md lg:sticky top-0 z-40">
|
||||
<div class="container mx-auto flex items-center justify-between py-4 px-6">
|
||||
{% wagtail_site as current_site %}
|
||||
<a class="text-xl font-bold" href="/">{{ current_site.site_name }}</a>
|
||||
<nav class="flex items-center gap-4">
|
||||
<a class="text-xl font-bold" href="/">{{ current_site.site_name }}</a>
|
||||
<a href="{% slugurl 'courses' %}" class="hover:underline">{% trans "Courses" %}</a>
|
||||
<a href="{% slugurl 'blog' %}" class="hover:underline">{% trans "Blog" %}</a>
|
||||
<a href="{% url 'calendar' %}" class="hover:underline">{% trans "Calendar" %}</a>
|
||||
<a href="{% url 'user_chat' %}" class="hover:underline">{% trans "Help" %}</a>
|
||||
</nav>
|
||||
|
||||
<nav class="flex items-center gap-4">
|
||||
<a href="{% url 'calendar' %}" class="hover:underline">{% trans "Course Calendar" %}</a>
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'account_logout' %}" class="hover:underline">{% trans "Logout" %}</a>
|
||||
{% else %}
|
||||
@@ -28,8 +33,8 @@
|
||||
</div>
|
||||
|
||||
<div class="container mx-auto px-6 mb-2 md:mb-0">
|
||||
<form action="{% url 'search' %}" method="get" class="flex items-center bg-blue-950 rounded-md md:w-auto md:absolute md:left-1/2 md:top-1/2 md:transform md:-translate-x-1/2 md:-translate-y-1/2 md:mt-0">
|
||||
<input type="text" name="query" placeholder="{% trans 'Search courses...' %}" class="rounded-md px-3 py-2 w-full md:w-auto focus:outline-none">
|
||||
<form action="{% url 'search' %}" method="get" class="flex items-center bg-blue-950 rounded-md mb-2 lg:w-auto lg:absolute lg:left-1/2 lg:top-1/2 lg:transform lg:-translate-x-1/2 lg:-translate-y-1/2 lg:mt-0">
|
||||
<input type="text" name="query" placeholder="{% trans 'Search courses...' %}" class="rounded-lg px-3 py-2 w-full lg:w-auto focus:outline-none">
|
||||
<button type="submit" class="bg-white text-blue-900 rounded-md px-3 py-2 hover:bg-gray-200 transition"><i class="fi fi-br-search"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,9 @@ urlpatterns = [
|
||||
path("accounts/profile/", views.profile, name="profile"),
|
||||
path("accounts/signup/", views.signup, name="signup"),
|
||||
path("i18n/", include("django.conf.urls.i18n")),
|
||||
path("oauth2/", include("oauth2_provider.urls", namespace="oauth2_provider")),
|
||||
path("", include("home.urls")),
|
||||
path("", include("purchase.urls")),
|
||||
path("calendar/", views.calendar, name="calendar"),
|
||||
# TODO: move occurrence related urls to home app
|
||||
path(
|
||||
|
||||
0
purchase/__init__.py
Normal file
0
purchase/__init__.py
Normal file
3
purchase/admin.py
Normal file
3
purchase/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
5
purchase/apps.py
Normal file
5
purchase/apps.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PurchaseConfig(AppConfig):
|
||||
name = 'purchase'
|
||||
28
purchase/migrations/0001_initial.py
Normal file
28
purchase/migrations/0001_initial.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 6.0.3 on 2026-03-19 17:36
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('home', '0019_coursepage_description'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CoursePurchase',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('purchased_at', models.DateTimeField(auto_now_add=True)),
|
||||
('refunded', models.BooleanField(default=False)),
|
||||
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='home.coursepage')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
purchase/migrations/__init__.py
Normal file
0
purchase/migrations/__init__.py
Normal file
134
purchase/models.py
Normal file
134
purchase/models.py
Normal file
@@ -0,0 +1,134 @@
|
||||
import logging as lg
|
||||
import os
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db import models
|
||||
|
||||
GITEA_ORG_NAME = "Studio77"
|
||||
logger = lg.getLogger(__name__)
|
||||
|
||||
|
||||
class CoursePurchase(models.Model):
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
course = models.ForeignKey("home.CoursePage", on_delete=models.CASCADE)
|
||||
purchased_at = models.DateTimeField(auto_now_add=True)
|
||||
refunded = models.BooleanField(default=False)
|
||||
|
||||
def mock_refund(self):
|
||||
self.refunded = True
|
||||
self.save()
|
||||
|
||||
def _get_gitea_team_id(self, team_name):
|
||||
api_url = getattr(settings, "GITEA_URL", None)
|
||||
if not api_url:
|
||||
logger.debug("GITEA_URL is not set, skipping Gitea team assignment")
|
||||
return None
|
||||
|
||||
try:
|
||||
response = requests.get(
|
||||
f"{api_url}/orgs/{GITEA_ORG_NAME}/teams",
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
teams = response.json()
|
||||
team = next((team for team in teams if team["name"] == team_name), None)
|
||||
return team["id"] if team else None
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Failed to check existing Gitea teams: {e}\n{getattr(response, 'text', '')}",
|
||||
e,
|
||||
)
|
||||
return None
|
||||
|
||||
def add_to_gitea_team(self):
|
||||
course = self.course
|
||||
user = self.user
|
||||
team_name = f"course-{course.id}"
|
||||
api_url = getattr(settings, "GITEA_URL", None)
|
||||
|
||||
if not api_url:
|
||||
logger.debug("GITEA_URL is not set, skipping Gitea team assignment")
|
||||
return
|
||||
|
||||
team_id = self._get_gitea_team_id(team_name)
|
||||
if not team_id:
|
||||
logger.warning(
|
||||
f"Gitea team {team_name} not found for course {course.title}"
|
||||
)
|
||||
return
|
||||
|
||||
url = f"{api_url}/teams/{team_id}/members/studio77-{user.id}"
|
||||
try:
|
||||
response = requests.put(
|
||||
url,
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
if response.status_code == 204:
|
||||
logger.info(
|
||||
f"Successfully added user {user.email} to Gitea team {team_name}"
|
||||
)
|
||||
else:
|
||||
response.raise_for_status()
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Failed to add user {user.email} to Gitea team {team_name}: {e}\n{getattr(response, 'text', '')}"
|
||||
)
|
||||
|
||||
def remove_from_gitea_team(self):
|
||||
course = self.course
|
||||
user = self.user
|
||||
team_name = f"course-{course.id}"
|
||||
api_url = getattr(settings, "GITEA_URL", None)
|
||||
|
||||
if not api_url:
|
||||
logger.debug("GITEA_URL is not set, skipping Gitea team removal")
|
||||
return
|
||||
|
||||
team_id = self._get_gitea_team_id(team_name)
|
||||
if not team_id:
|
||||
logger.warning(
|
||||
f"Gitea team {team_name} not found for course {course.title}"
|
||||
)
|
||||
return
|
||||
|
||||
url = f"{api_url}/teams/{team_id}/members/studio77-{user.id}"
|
||||
try:
|
||||
response = requests.delete(
|
||||
url,
|
||||
timeout=5,
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_API_TOKEN')}"},
|
||||
)
|
||||
if response.status_code == 204:
|
||||
logger.info(
|
||||
f"Successfully removed user {user.email} from Gitea team {team_name}"
|
||||
)
|
||||
else:
|
||||
response.raise_for_status()
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Failed to remove user {user.email} from Gitea team {team_name}: {e}\n{getattr(response, 'text', '')}"
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
group_name = f"course_{self.course.id}_access"
|
||||
|
||||
group, _ = Group.objects.get_or_create(name=group_name)
|
||||
|
||||
print(
|
||||
f"Saving CoursePurchase for user {self.user} and course {self.course.title}, refunded={self.refunded}"
|
||||
)
|
||||
|
||||
if self.refunded:
|
||||
print(f"Removing user {self.user} from group {group_name} due to refund")
|
||||
self.remove_from_gitea_team()
|
||||
self.user.groups.remove(group)
|
||||
else:
|
||||
logger.debug(
|
||||
f"Adding user {self.user} to group {group_name} for course {self.course.title}"
|
||||
)
|
||||
self.add_to_gitea_team()
|
||||
3
purchase/tests.py
Normal file
3
purchase/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
16
purchase/urls.py
Normal file
16
purchase/urls.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"mock-purchase/<int:course_id>/",
|
||||
views.mock_purchase_course,
|
||||
name="mock_purchase_course",
|
||||
),
|
||||
path(
|
||||
"mock-refund/<int:purchase_id>/",
|
||||
views.mock_refund_purchase,
|
||||
name="mock_refund_purchase",
|
||||
),
|
||||
]
|
||||
21
purchase/views.py
Normal file
21
purchase/views.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
|
||||
from home.models import CoursePage
|
||||
from purchase.models import CoursePurchase
|
||||
|
||||
|
||||
def mock_purchase_course(request, course_id):
|
||||
course = CoursePage.objects.get(id=course_id)
|
||||
|
||||
course.mock_purchase(request.user)
|
||||
|
||||
return redirect(course.url)
|
||||
|
||||
|
||||
def mock_refund_purchase(request, purchase_id):
|
||||
purchase = CoursePurchase.objects.get(id=purchase_id)
|
||||
|
||||
purchase.mock_refund()
|
||||
|
||||
return redirect(purchase.course.url)
|
||||
@@ -8,10 +8,14 @@ dependencies = [
|
||||
"django-allauth-ui>=1.8.1",
|
||||
"django-allauth[socialaccount]>=65.15.0",
|
||||
"django-browser-reload>=1.21.0",
|
||||
"django-oauth-toolkit>=3.2.0",
|
||||
"django-tailwind>=4.4.2",
|
||||
"django-widget-tweaks>=1.5.1",
|
||||
"gunicorn>=25.3.0",
|
||||
"python-dotenv>=1.2.2",
|
||||
"slippers>=0.6.2",
|
||||
"uvicorn>=0.42.0",
|
||||
"uvicorn-worker>=0.4.0",
|
||||
"wagtail==7.3rc1",
|
||||
"wagtail-color-panel>=1.7.1",
|
||||
"wagtailmedia>=0.17.2",
|
||||
|
||||
376
uv.lock
generated
376
uv.lock
generated
@@ -57,11 +57,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2026.2.25"
|
||||
version = "2026.4.22"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -99,39 +99,55 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.4.5"
|
||||
version = "3.4.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/43/be/0f0fd9bb4a7fa4fb5067fb7d9ac693d4e928d306f80a0d02bde43a7c4aee/charset_normalizer-3.4.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8197abe5ca1ffb7d91e78360f915eef5addff270f8a71c1fc5be24a56f3e4873", size = 280232, upload-time = "2026-03-06T06:02:01.508Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/02/983b5445e4bef49cd8c9da73a8e029f0825f39b74a06d201bfaa2e55142a/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2aecdb364b8a1802afdc7f9327d55dad5366bc97d8502d0f5854e50712dbc5f", size = 189688, upload-time = "2026-03-06T06:02:02.857Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/88/152745c5166437687028027dc080e2daed6fe11cfa95a22f4602591c42db/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a66aa5022bf81ab4b1bebfb009db4fd68e0c6d4307a1ce5ef6a26e5878dfc9e4", size = 206833, upload-time = "2026-03-06T06:02:05.127Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/0f/ebc15c8b02af2f19be9678d6eed115feeeccc45ce1f4b098d986c13e8769/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d77f97e515688bd615c1d1f795d540f32542d514242067adcb8ef532504cb9ee", size = 202879, upload-time = "2026-03-06T06:02:06.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/9c/71336bff6934418dc8d1e8a1644176ac9088068bc571da612767619c97b3/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01a1ed54b953303ca7e310fafe0fe347aab348bd81834a0bcd602eb538f89d66", size = 195764, upload-time = "2026-03-06T06:02:08.763Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/95/ce92fde4f98615661871bc282a856cf9b8a15f686ba0af012984660d480b/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:b2d37d78297b39a9eb9eb92c0f6df98c706467282055419df141389b23f93362", size = 183728, upload-time = "2026-03-06T06:02:10.137Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/e7/f5b4588d94e747ce45ae680f0f242bc2d98dbd4eccfab73e6160b6893893/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e71bbb595973622b817c042bd943c3f3667e9c9983ce3d205f973f486fec98a7", size = 192937, upload-time = "2026-03-06T06:02:11.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/29/9d94ed6b929bf9f48bf6ede6e7474576499f07c4c5e878fb186083622716/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cd966c2559f501c6fd69294d082c2934c8dd4719deb32c22961a5ac6db0df1d", size = 192040, upload-time = "2026-03-06T06:02:13.489Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/d2/1a093a1cf827957f9445f2fe7298bcc16f8fc5e05c1ed2ad1af0b239035e/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d5e52d127045d6ae01a1e821acfad2f3a1866c54d0e837828538fabe8d9d1bd6", size = 184107, upload-time = "2026-03-06T06:02:14.83Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/7d/82068ce16bd36135df7b97f6333c5d808b94e01d4599a682e2337ed5fd14/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:30a2b1a48478c3428d047ed9690d57c23038dac838a87ad624c85c0a78ebeb39", size = 208310, upload-time = "2026-03-06T06:02:16.165Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/4e/4dfb52307bb6af4a5c9e73e482d171b81d36f522b21ccd28a49656baa680/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d8ed79b8f6372ca4254955005830fd61c1ccdd8c0fac6603e2c145c61dd95db6", size = 192918, upload-time = "2026-03-06T06:02:18.144Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/a4/159ff7da662cf7201502ca89980b8f06acf3e887b278956646a8aeb178ab/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c5af897b45fa606b12464ccbe0014bbf8c09191e0a66aab6aa9d5cf6e77e0c94", size = 204615, upload-time = "2026-03-06T06:02:19.821Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/62/0dd6172203cb6b429ffffc9935001fde42e5250d57f07b0c28c6046deb6b/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1088345bcc93c58d8d8f3d783eca4a6e7a7752bbff26c3eee7e73c597c191c2e", size = 197784, upload-time = "2026-03-06T06:02:21.86Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/5e/1aab5cb737039b9c59e63627dc8bbc0d02562a14f831cc450e5f91d84ce1/charset_normalizer-3.4.5-cp314-cp314-win32.whl", hash = "sha256:ee57b926940ba00bca7ba7041e665cc956e55ef482f851b9b65acb20d867e7a2", size = 133009, upload-time = "2026-03-06T06:02:23.289Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/65/e7c6c77d7aaa4c0d7974f2e403e17f0ed2cb0fc135f77d686b916bf1eead/charset_normalizer-3.4.5-cp314-cp314-win_amd64.whl", hash = "sha256:4481e6da1830c8a1cc0b746b47f603b653dadb690bcd851d039ffaefe70533aa", size = 143511, upload-time = "2026-03-06T06:02:26.195Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/91/52b0841c71f152f563b8e072896c14e3d83b195c188b338d3cc2e582d1d4/charset_normalizer-3.4.5-cp314-cp314-win_arm64.whl", hash = "sha256:97ab7787092eb9b50fb47fa04f24c75b768a606af1bcba1957f07f128a7219e4", size = 133775, upload-time = "2026-03-06T06:02:27.473Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.3.1"
|
||||
version = "8.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", size = 328061, upload-time = "2026-04-22T15:11:27.506Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", size = 110502, upload-time = "2026-04-22T15:11:25.044Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -164,55 +180,55 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "46.0.5"
|
||||
version = "46.0.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", size = 7119671, upload-time = "2026-04-08T01:56:44Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", size = 4268551, upload-time = "2026-04-08T01:56:46.071Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", size = 4408887, upload-time = "2026-04-08T01:56:47.718Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", size = 4271354, upload-time = "2026-04-08T01:56:49.312Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", size = 4905845, upload-time = "2026-04-08T01:56:50.916Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", size = 4444641, upload-time = "2026-04-08T01:56:52.882Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", size = 3967749, upload-time = "2026-04-08T01:56:54.597Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", size = 4270942, upload-time = "2026-04-08T01:56:56.416Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", size = 4871079, upload-time = "2026-04-08T01:56:58.31Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", size = 4443999, upload-time = "2026-04-08T01:57:00.508Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", size = 4399191, upload-time = "2026-04-08T01:57:02.654Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", size = 4655782, upload-time = "2026-04-08T01:57:04.592Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", size = 3002227, upload-time = "2026-04-08T01:57:06.91Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", size = 3475332, upload-time = "2026-04-08T01:57:08.807Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -226,29 +242,29 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "6.0.3"
|
||||
version = "6.0.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asgiref" },
|
||||
{ name = "sqlparse" },
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/80/e1/894115c6bd70e2c8b66b0c40a3c367d83a5a48c034a4d904d31b62f7c53a/django-6.0.3.tar.gz", hash = "sha256:90be765ee756af8a6cbd6693e56452404b5ad15294f4d5e40c0a55a0f4870fe1", size = 10872701, upload-time = "2026-03-03T13:55:15.026Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/60/b9/4155091ad1788b38563bd77a7258c0834e8c12a7f56f6975deaf54f8b61d/django-6.0.4.tar.gz", hash = "sha256:8cfa2572b3f2768b2e84983cf3c4811877a01edb64e817986ec5d60751c113ac", size = 10907407, upload-time = "2026-04-07T13:55:44.961Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/72/b1/23f2556967c45e34d3d3cf032eb1bd3ef925ee458667fb99052a0b3ea3a6/django-6.0.3-py3-none-any.whl", hash = "sha256:2e5974441491ddb34c3f13d5e7a9f97b07ba03bf70234c0a9c68b79bbb235bc3", size = 8358527, upload-time = "2026-03-03T13:55:10.552Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/47/3d61d611609764aa71a37f7037b870e7bfb22937366974c4fd46cada7bab/django-6.0.4-py3-none-any.whl", hash = "sha256:14359c809fc16e8f81fd2b59d7d348e4d2d799da6840b10522b6edf7b8afc1da", size = 8368342, upload-time = "2026-04-07T13:55:37.999Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-allauth"
|
||||
version = "65.15.0"
|
||||
version = "65.16.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asgiref" },
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/84/c1/d3385f4c3169c1d6eea3c63aed0f36af51478c1d72e46db12bb1a08f8034/django_allauth-65.15.0.tar.gz", hash = "sha256:b404d48cf0c3ee14dacc834c541f30adedba2ff1c433980ecc494d6cb0b395a8", size = 2215709, upload-time = "2026-03-09T13:51:28.675Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/df/357187dfff18c7783e4911827a6c69437e290d7259a32a99c23fcd85997f/django_allauth-65.16.1.tar.gz", hash = "sha256:4425ac3088541c4c54983e16e08f6e3eb9f438dc1b1009534fa51c8bb739ed31", size = 2232835, upload-time = "2026-04-17T18:53:59.475Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/75/b8/c8411339171bd8bc075c09ef190fb42195e9a2149e5c5026e094fe62fce0/django_allauth-65.15.0-py3-none-any.whl", hash = "sha256:ad9fc49c49a9368eaa5bb95456b76e2a4f377b3c6862ee8443507816578c098d", size = 2022994, upload-time = "2026-03-09T13:51:19.711Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/58/d95b6c3088d83697bfd93782ee57bc6a6462e41eb19121a947b8a015396a/django_allauth-65.16.1-py3-none-any.whl", hash = "sha256:e49df24056bf37c44e56aaad1e51f78994b7d175bc3476d65e8f8f58390a8ce8", size = 2051868, upload-time = "2026-04-17T18:54:12.032Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -308,6 +324,21 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/e4/ec99d52aa04e204e938564b603f4591e2e82e236ed59af664fee35179e75/django_modelcluster-6.4.1-py2.py3-none-any.whl", hash = "sha256:ccc190cd9e22c24900ea2410bff64d444d48f43f0f4aedeed0f6cd94e2536698", size = 29315, upload-time = "2025-12-04T12:21:39.911Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-oauth-toolkit"
|
||||
version = "3.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
{ name = "jwcrypto" },
|
||||
{ name = "oauthlib" },
|
||||
{ name = "requests" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a7/95/efd83b35c34b86eb2249d2b54c5eaf383c48f3f19034aa6f3807e37471b6/django_oauth_toolkit-3.2.0.tar.gz", hash = "sha256:c36761ae6810083d95a652e9c820046cde0d45a2e2a5574bbe7202656ec20bb6", size = 114211, upload-time = "2026-01-08T22:03:13.311Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/cc/f27a784c0ecd13335abd9ef85ebb80dbc04945f919da5f496f56e3562751/django_oauth_toolkit-3.2.0-py3-none-any.whl", hash = "sha256:bd2cd2719b010231a2f370f927dbcc740454fb1d0dd7e7f4138f36227363dc26", size = 87077, upload-time = "2026-01-08T22:03:12.123Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-permissionedforms"
|
||||
version = "0.1"
|
||||
@@ -322,15 +353,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "django-stubs-ext"
|
||||
version = "5.2.9"
|
||||
version = "6.0.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/55/03/9c2be939490d2282328db4611bc5956899f5ff7eabc3e88bd4b964a87373/django_stubs_ext-5.2.9.tar.gz", hash = "sha256:6db4054d1580657b979b7d391474719f1a978773e66c7070a5e246cd445a25a9", size = 6497, upload-time = "2026-01-20T23:58:59.462Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fb/e6/5dcdaa785ec3eed5fc196c7e68fb7ad9d9fe6d5acccea4690e65f2546417/django_stubs_ext-6.0.3.tar.gz", hash = "sha256:3307d42132bc295d5744de6276bc5fdf6896efc70f891e21c0ae8bdf529d2762", size = 6663, upload-time = "2026-04-18T15:10:53.667Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/f7/0d5f7d7e76fe972d9f560f687fdc0cab4db9e1624fd90728ca29b4ed7a63/django_stubs_ext-5.2.9-py3-none-any.whl", hash = "sha256:230c51575551b0165be40177f0f6805f1e3ebf799b835c85f5d64c371ca6cf71", size = 9974, upload-time = "2026-01-20T23:58:58.438Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/fa/0a3a05c29d6295dbd52fa3cb4047a95de11ba4f2696072d6f3f2c1e6f370/django_stubs_ext-6.0.3-py3-none-any.whl", hash = "sha256:9e4105955419ae310d7da9cfd808e039d4dae3092c628f021057bb4f2c237f8f", size = 10354, upload-time = "2026-04-18T15:10:52.395Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -398,14 +429,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "djangorestframework"
|
||||
version = "3.16.1"
|
||||
version = "3.17.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8a/95/5376fe618646fde6899b3cdc85fd959716bb67542e273a76a80d9f326f27/djangorestframework-3.16.1.tar.gz", hash = "sha256:166809528b1aced0a17dc66c24492af18049f2c9420dbd0be29422029cfc3ff7", size = 1089735, upload-time = "2025-08-06T17:50:53.251Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/d7/c016e69fac19ff8afdc89db9d31d9ae43ae031e4d1993b20aca179b8301a/djangorestframework-3.17.1.tar.gz", hash = "sha256:a6def5f447fe78ff853bff1d47a3c59bf38f5434b031780b351b0c73a62db1a5", size = 905742, upload-time = "2026-03-24T16:58:33.705Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/ce/bf8b9d3f415be4ac5588545b5fcdbbb841977db1c1d923f7568eeabe1689/djangorestframework-3.16.1-py3-none-any.whl", hash = "sha256:33a59f47fb9c85ede792cbf88bde71893bcda0667bc573f784649521f1102cec", size = 1080442, upload-time = "2025-08-06T17:50:50.667Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl", hash = "sha256:c3c74dd3e83a5a3efc37b3c18d92bd6f86a6791c7b7d4dff62bb068500e76457", size = 898844, upload-time = "2026-03-24T16:58:31.845Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -436,12 +467,33 @@ wheels = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.11"
|
||||
name = "gunicorn"
|
||||
version = "25.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
|
||||
dependencies = [
|
||||
{ name = "packaging" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c4/f4/e78fa054248fab913e2eab0332c6c2cb07421fca1ce56d8fe43b6aef57a4/gunicorn-25.3.0.tar.gz", hash = "sha256:f74e1b2f9f76f6cd1ca01198968bd2dd65830edc24b6e8e4d78de8320e2fe889", size = 634883, upload-time = "2026-03-27T00:00:26.092Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/c8/8aaf447698c4d59aa853fd318eed300b5c9e44459f242ab8ead6c9c09792/gunicorn-25.3.0-py3-none-any.whl", hash = "sha256:cacea387dab08cd6776501621c295a904fe8e3b7aae9a1a3cbb26f4e7ed54660", size = 208403, upload-time = "2026-03-27T00:00:27.386Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
version = "0.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.13"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -456,6 +508,19 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jwcrypto"
|
||||
version = "1.5.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/90/f065668004d22715c1940d6e88e4c3afc8ee16d5664e4478d2c8fd23a250/jwcrypto-1.5.7.tar.gz", hash = "sha256:70204d7cca406eda8c82352e3c41ba2d946610dafd19e54403f0a1f4f18633c6", size = 89535, upload-time = "2026-04-07T00:35:36.116Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/72/24/fb7da4d6613de7001feaf540d4b5969c6b5a1c42839043b0196cb13aa057/jwcrypto-1.5.7-py3-none-any.whl", hash = "sha256:729463fefe28b6de5cf1ebfda3e94f1a1b41d2799148ef98a01cb9678ebe2bb0", size = 94799, upload-time = "2026-04-07T00:35:35.085Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kursy"
|
||||
version = "0.1.0"
|
||||
@@ -466,10 +531,14 @@ dependencies = [
|
||||
{ name = "django-allauth", extra = ["socialaccount"] },
|
||||
{ name = "django-allauth-ui" },
|
||||
{ name = "django-browser-reload" },
|
||||
{ name = "django-oauth-toolkit" },
|
||||
{ name = "django-tailwind" },
|
||||
{ name = "django-widget-tweaks" },
|
||||
{ name = "gunicorn" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "slippers" },
|
||||
{ name = "uvicorn" },
|
||||
{ name = "uvicorn-worker" },
|
||||
{ name = "wagtail" },
|
||||
{ name = "wagtail-color-panel" },
|
||||
{ name = "wagtailmedia" },
|
||||
@@ -482,10 +551,14 @@ requires-dist = [
|
||||
{ name = "django-allauth", extras = ["socialaccount"], specifier = ">=65.15.0" },
|
||||
{ name = "django-allauth-ui", specifier = ">=1.8.1" },
|
||||
{ name = "django-browser-reload", specifier = ">=1.21.0" },
|
||||
{ name = "django-oauth-toolkit", specifier = ">=3.2.0" },
|
||||
{ name = "django-tailwind", specifier = ">=4.4.2" },
|
||||
{ name = "django-widget-tweaks", specifier = ">=1.5.1" },
|
||||
{ name = "gunicorn", specifier = ">=25.3.0" },
|
||||
{ name = "python-dotenv", specifier = ">=1.2.2" },
|
||||
{ name = "slippers", specifier = ">=0.6.2" },
|
||||
{ name = "uvicorn", specifier = ">=0.42.0" },
|
||||
{ name = "uvicorn-worker", specifier = ">=0.4.0" },
|
||||
{ name = "wagtail", specifier = "==7.3rc1" },
|
||||
{ name = "wagtail-color-panel", specifier = ">=1.7.1" },
|
||||
{ name = "wagtailmedia", specifier = ">=0.17.2" },
|
||||
@@ -589,36 +662,45 @@ wheels = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "12.1.1"
|
||||
name = "packaging"
|
||||
version = "26.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/df/de/0d2b39fb4af88a0258f3bac87dfcbb48e73fbdea4a2ed0e2213f9a4c2f9a/packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de", size = 215519, upload-time = "2026-04-14T21:12:49.362Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/c2/920ef838e2f0028c8262f16101ec09ebd5969864e5a64c4c05fad0617c56/packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f", size = 95831, upload-time = "2026-04-14T21:12:47.56Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "12.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -657,20 +739,20 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.19.2"
|
||||
version = "2.20.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyjwt"
|
||||
version = "2.11.0"
|
||||
version = "2.12.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -748,7 +830,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.32.5"
|
||||
version = "2.33.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
@@ -756,22 +838,22 @@ dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "14.3.3"
|
||||
version = "15.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -785,7 +867,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "slippers"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
@@ -793,9 +875,9 @@ dependencies = [
|
||||
{ name = "typeguard" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a7/c6/6af4500f31e53e9f782d264cb715f1a8cc9ac4248fba9fe2fe172822ea79/slippers-0.6.2.tar.gz", hash = "sha256:4cb555b8822ba0d404e5405723f5d723994022c29046008ee917081031bc0cf1", size = 59499, upload-time = "2023-08-01T05:04:18.964Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/3c/979ab01ee6515fb3d6f10cfc10ef2e6219817828b972c54d49f6ddd9ddd2/slippers-0.6.3.tar.gz", hash = "sha256:8602f462da79b707d25ec050fb51b6cbe5fb225b3c7faf40d1f02876d970e9f0", size = 59793, upload-time = "2026-03-30T04:51:59.436Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/8c/1fe2803870861f9a7f0cf502e4d1361dbb3685997118f4f76fd83ec9272f/slippers-0.6.2-py3-none-any.whl", hash = "sha256:739e05f85354becbf0a65daab831eea62557d89e7512042209ab629af4378bca", size = 61359, upload-time = "2023-08-01T05:04:17.378Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/b9/76c4b0535d26089d0d01f5c9cb3529b121babd1abf605e6c7e12acedb09b/slippers-0.6.3-py3-none-any.whl", hash = "sha256:cddd92cb998fb48472f863a811566f5a187b392f65ae4b0df81008b56dff214c", size = 62528, upload-time = "2026-03-30T04:51:58.227Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -854,11 +936,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2025.3"
|
||||
version = "2026.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639, upload-time = "2026-04-03T11:25:22.002Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952, upload-time = "2026-04-03T11:25:20.313Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -870,6 +952,32 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.45.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/62b0d9a2cfc8b4de6771322dae30f2db76c66dae9ec32e94e176a44ad563/uvicorn-0.45.0.tar.gz", hash = "sha256:3fe650df136c5bd2b9b06efc5980636344a2fbb840e9ddd86437d53144fa335d", size = 87818, upload-time = "2026-04-21T10:43:46.815Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/88/d0f7512465b166a4e931ccf7e77792be60fb88466a43964c7566cbaff752/uvicorn-0.45.0-py3-none-any.whl", hash = "sha256:2db26f588131aeec7439de00f2dd52d5f210710c1f01e407a52c90b880d1fd4f", size = 69838, upload-time = "2026-04-21T10:43:45.029Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn-worker"
|
||||
version = "0.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "gunicorn" },
|
||||
{ name = "uvicorn" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/80/59/9101b9c0680fd80e9d26c07deb822a5d18a324339fcf9cd017885ee808ad/uvicorn_worker-0.4.0.tar.gz", hash = "sha256:8ee5306070d8f38dce124adce488c3c0b50f20cf0c0222b12c66188da7214493", size = 9361, upload-time = "2025-09-20T10:47:01.218Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/90/25/09cd7a90c8bb7fb693be0d6704fccd5f9778d5513214b7a01cc4a94ff314/uvicorn_worker-0.4.0-py3-none-any.whl", hash = "sha256:e2ed952cef976f5e9e429d7269640bbcafbd36c80aa80f1003c8c77a6797abde", size = 5364, upload-time = "2025-09-20T10:46:59.776Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wagtail"
|
||||
version = "7.3rc1"
|
||||
@@ -901,14 +1009,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "wagtail-color-panel"
|
||||
version = "1.7.1"
|
||||
version = "1.8.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "wagtail" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/58/bd/043c8cfc6eae14303b555782add80148db0596441e8770723cf17e664d4d/wagtail_color_panel-1.7.1.tar.gz", hash = "sha256:efc42058a49c39bea6a61523b230c71cf31e5aeaa269281c53146eeec02fc509", size = 10315, upload-time = "2025-11-23T06:07:53.765Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9e/44/bd3e5a9ee9bc9b72153e0a227aae5b7e181d2ce4e601ff9b01c1074fbbb5/wagtail_color_panel-1.8.1.tar.gz", hash = "sha256:aca26f8b7178ff596aa2eac8982167396bbbc222fadbae4b6b1f18291b33473a", size = 10776, upload-time = "2026-04-12T19:16:14.464Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/db/1d/d004a5b57c8b1db6edee953e3222436c050dff2667320ca345964551640a/wagtail_color_panel-1.7.1-py3-none-any.whl", hash = "sha256:77ee02a6dd08b21e8806bb3e8c7dc01ad679dbeef864ad915fec32f5e8bcd574", size = 9383, upload-time = "2025-11-23T06:07:52.733Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/bb/86ee676a4613c0dade91685fb3402766de4c20874ad6f18d91807d9813cc/wagtail_color_panel-1.8.1-py3-none-any.whl", hash = "sha256:6e8aaeceac3618a9b69370b5097fa4d3c2db19b31bff95b7726343660793e55e", size = 9256, upload-time = "2026-04-12T19:16:13.68Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user