feat(features-complete): features complete version without tests, build and CICD pipelines

BREAKING CHANGE:
main
flavien 2023-06-17 13:46:44 +00:00
parent c1833ac42b
commit e1c1e957f8
32 changed files with 2619 additions and 28 deletions

View File

@ -1,6 +1,11 @@
ARG VARIANT=18-bullseye
FROM mcr.microsoft.com/devcontainers/python:3.11-bullseye
RUN apt install curl
RUN curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -
RUN apt install nodejs
RUN pip install --upgrade pip
RUN pip install poetry
RUN git config --global --add safe.directory /workspace

View File

@ -3,13 +3,13 @@
"customizations": {
"vscode": {
"extensions": [
"formulahendry.terminal",
"ms-python.python",
"bungcip.better-toml",
"batisteo.vscode-django",
"mtxr.sqltools",
"mtxr.sqltools-driver-pg",
"GitHub.copilot"
"GitHub.copilot-nightly",
"GitHub.copilot-chat"
],
"settings": {
"terminal.integrated.profiles.linux": {

View File

@ -5,7 +5,7 @@ services:
build: .
volumes:
- ../:/workspace:cached
- ~/.ssh:/root/.ssh:cached
- ssh:/root/.ssh
command: /bin/sh -c "while sleep 1000; do :; done"
links:
- postgres
@ -29,4 +29,5 @@ networks:
postgres:
volumes:
postgres:
postgres:
ssh:

View File

@ -10,14 +10,14 @@ repos:
files: ^unicorn_post/
- id: mypy
name: mypy
entry: bash -c 'cd unicorn_post && mypy .'
entry: mypy unicorn_post
language: system
pass_filenames: false
types: [python]
files: ^unicorn_post/
- id: pylint
name: pylint
entry: pylint unicorn_post/*
entry: pylint --recursive y unicorn_post
language: system
pass_filenames: false
types: [python]
@ -28,4 +28,10 @@ repos:
language: system
pass_filenames: false
types: [python]
files: ^unicorn_post/
files: ^unicorn_post/
- repo: https://github.com/commitizen-tools/commitizen
rev: master
hooks:
- id: commitizen
- id: commitizen-branch
stages: [push]

View File

@ -1,4 +0,0 @@
[MESSAGES CONTROL]
disable=
# django
import-outside-toplevel,

14
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,14 @@
{
"sqltools.connections": [
{
"previewLimit": 50,
"server": "postgres",
"port": 5432,
"driver": "PostgreSQL",
"name": "dev_db",
"database": "unicorn_post_db",
"username": "galactic",
"password": "unicorn"
}
]
}

View File

@ -22,10 +22,6 @@ The `.devcontainer` folder also contains a db.env file which is used to configur
## TODO
- [ ] Add a CI pipeline
- [ ] Implement home page with auth
- [ ] Implement message form
- [ ] Implement MQTT proxy
- [ ] Implement message model
- [ ] Add a test suite
- [ ] Add a CD pipeline
- [ ] Add semantic versioning

545
poetry.lock generated
View File

@ -1,5 +1,19 @@
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
[[package]]
name = "argcomplete"
version = "3.0.8"
description = "Bash tab completion for argparse"
optional = false
python-versions = ">=3.6"
files = [
{file = "argcomplete-3.0.8-py3-none-any.whl", hash = "sha256:e36fd646839933cbec7941c662ecb65338248667358dd3d968405a4506a60d9b"},
{file = "argcomplete-3.0.8.tar.gz", hash = "sha256:b9ca96448e14fa459d7450a4ab5a22bbf9cee4ba7adddf03e65c398b5daeea28"},
]
[package.extras]
test = ["coverage", "mypy", "pexpect", "ruff", "wheel"]
[[package]]
name = "asgiref"
version = "3.7.2"
@ -29,6 +43,24 @@ files = [
lazy-object-proxy = ">=1.4.0"
wrapt = {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}
[[package]]
name = "beautifulsoup4"
version = "4.12.2"
description = "Screen-scraping library"
optional = false
python-versions = ">=3.6.0"
files = [
{file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"},
{file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"},
]
[package.dependencies]
soupsieve = ">1.2"
[package.extras]
html5lib = ["html5lib"]
lxml = ["lxml"]
[[package]]
name = "black"
version = "23.3.0"
@ -76,6 +108,17 @@ d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "cachetools"
version = "4.2.4"
description = "Extensible memoizing collections and decorators"
optional = false
python-versions = "~=3.5"
files = [
{file = "cachetools-4.2.4-py3-none-any.whl", hash = "sha256:92971d3cb7d2a97efff7c7bb1657f21a8f5fb309a37530537c71b1774189f2d1"},
{file = "cachetools-4.2.4.tar.gz", hash = "sha256:89ea6f1b638d5a73a4f9226be57ac5e4f399d22770b92355f92dcb0f7f001693"},
]
[[package]]
name = "cfgv"
version = "3.3.1"
@ -87,6 +130,90 @@ files = [
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
]
[[package]]
name = "charset-normalizer"
version = "3.1.0"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7.0"
files = [
{file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"},
{file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"},
{file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"},
{file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"},
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"},
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"},
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"},
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"},
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"},
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"},
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"},
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"},
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"},
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"},
{file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"},
{file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"},
{file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"},
{file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"},
{file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"},
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"},
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"},
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"},
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"},
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"},
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"},
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"},
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"},
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"},
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"},
{file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"},
{file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"},
{file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"},
{file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"},
{file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"},
{file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"},
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"},
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"},
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"},
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"},
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"},
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"},
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"},
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"},
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"},
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"},
{file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"},
{file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"},
{file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"},
{file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"},
{file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"},
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"},
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"},
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"},
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"},
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"},
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"},
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"},
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"},
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"},
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"},
{file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"},
{file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"},
{file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"},
]
[[package]]
name = "click"
version = "8.1.3"
@ -112,6 +239,30 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "commitizen"
version = "3.3.0"
description = "Python commitizen client tool"
optional = false
python-versions = ">=3.7,<4.0"
files = [
{file = "commitizen-3.3.0-py3-none-any.whl", hash = "sha256:55a5e6dfb7b5815a0708532d63c22ef3433ac0d66a48d8f40a7f9ba7e56c8a2c"},
{file = "commitizen-3.3.0.tar.gz", hash = "sha256:b1d81366c9e6a3f426dbf72a34de043d826045a382aa8cd9bc7d9289e84e66a8"},
]
[package.dependencies]
argcomplete = ">=1.12.1,<3.1"
charset-normalizer = ">=2.1.0,<4"
colorama = ">=0.4.1,<0.5.0"
decli = ">=0.6.0,<0.7.0"
importlib_metadata = ">=4.13,<7"
jinja2 = ">=2.10.3"
packaging = ">=19"
pyyaml = ">=3.08"
questionary = ">=1.4.0,<2.0.0"
termcolor = ">=1.1,<3"
tomlkit = ">=0.5.3,<1.0.0"
[[package]]
name = "coverage"
version = "7.2.7"
@ -184,6 +335,28 @@ files = [
[package.extras]
toml = ["tomli"]
[[package]]
name = "decli"
version = "0.6.1"
description = "Minimal, easy-to-use, declarative cli tool"
optional = false
python-versions = ">=3.7"
files = [
{file = "decli-0.6.1-py3-none-any.whl", hash = "sha256:7815ac58617764e1a200d7cadac6315fcaacc24d727d182f9878dd6378ccf869"},
{file = "decli-0.6.1.tar.gz", hash = "sha256:ed88ccb947701e8e5509b7945fda56e150e2ac74a69f25d47ac85ef30ab0c0f0"},
]
[[package]]
name = "decorator"
version = "4.4.2"
description = "Decorators for Humans"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
files = [
{file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"},
{file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"},
]
[[package]]
name = "dill"
version = "0.3.6"
@ -229,6 +402,20 @@ tzdata = {version = "*", markers = "sys_platform == \"win32\""}
argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"]
[[package]]
name = "django-browser-reload"
version = "1.9.0"
description = "Automatically reload your browser in development."
optional = false
python-versions = ">=3.7"
files = [
{file = "django_browser_reload-1.9.0-py3-none-any.whl", hash = "sha256:f8017d33fa8e72e6038f2a6a6e5215d1ff2ce1d2be49957722a0919d5fb1e6e0"},
{file = "django_browser_reload-1.9.0.tar.gz", hash = "sha256:4384cccd49580b4d60f3266166462912b771e55e510fdb1a945270862209b799"},
]
[package.dependencies]
Django = ">=3.2"
[[package]]
name = "django-stubs"
version = "4.2.1"
@ -269,6 +456,45 @@ files = [
django = "*"
typing-extensions = "*"
[[package]]
name = "django-tailwind"
version = "3.5.0"
description = "Tailwind CSS Framework for Django projects"
optional = false
python-versions = ">=3.8.1,<4.0.0"
files = [
{file = "django_tailwind-3.5.0-py3-none-any.whl", hash = "sha256:dcc3b29463fff48a0e8ccd15c87fd467f0e746a7987bde0fdde6253dbb7861be"},
{file = "django_tailwind-3.5.0.tar.gz", hash = "sha256:c089b05b47d0e9d19567a81a74949fde16cbbfd8e4264c1f8eb4216a644065b2"},
]
[package.dependencies]
django = ">=3.2.14"
django-browser-reload = ">=1.6.0,<2.0.0"
[[package]]
name = "django-unicorn"
version = "0.51.1"
description = "A magical full-stack framework for Django."
optional = false
python-versions = ">=3.7,<4"
files = [
{file = "django_unicorn-0.51.1-py3-none-any.whl", hash = "sha256:75acb0c52308f22e9d91bee094360247962403557bb278b8add9a05e86ef959d"},
{file = "django_unicorn-0.51.1.tar.gz", hash = "sha256:26fa9af3fe8ad594acc1099c316537157f9585bfef673eea44cc4445ae2772c0"},
]
[package.dependencies]
beautifulsoup4 = ">=4.8.0"
cachetools = ">=4.1.1,<5.0.0"
decorator = ">=4.4.2,<5.0.0"
django = ">=2.2"
htmlmin = {version = ">=0.1.12,<0.2.0", optional = true, markers = "extra == \"minify\""}
orjson = ">=3.6.0,<4.0.0"
shortuuid = ">=1.0.1,<2.0.0"
[package.extras]
docs = ["Sphinx (>=4.3.2,<5.0.0)", "furo (>=2021.11.23,<2022.0.0)", "linkify-it-py (>=1.0.3,<2.0.0)", "myst-parser (>=0.16.1,<0.17.0)", "rst2pdf (>=0.98,<0.99)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"]
minify = ["htmlmin (>=0.1.12,<0.2.0)"]
[[package]]
name = "filelock"
version = "3.12.0"
@ -284,6 +510,16 @@ files = [
docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
[[package]]
name = "htmlmin"
version = "0.1.12"
description = "An HTML Minifier"
optional = false
python-versions = "*"
files = [
{file = "htmlmin-0.1.12.tar.gz", hash = "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178"},
]
[[package]]
name = "identify"
version = "2.5.24"
@ -298,6 +534,25 @@ files = [
[package.extras]
license = ["ukkonen"]
[[package]]
name = "importlib-metadata"
version = "6.6.0"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.7"
files = [
{file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"},
{file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"},
]
[package.dependencies]
zipp = ">=0.5"
[package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
perf = ["ipython"]
testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
[[package]]
name = "isort"
version = "5.12.0"
@ -315,6 +570,23 @@ pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"
plugins = ["setuptools"]
requirements-deprecated-finder = ["pip-api", "pipreqs"]
[[package]]
name = "jinja2"
version = "3.1.2"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
files = [
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
]
[package.dependencies]
MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
[[package]]
name = "lazy-object-proxy"
version = "1.9.0"
@ -360,6 +632,65 @@ files = [
{file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"},
]
[[package]]
name = "markupsafe"
version = "2.1.3"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.7"
files = [
{file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
{file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
{file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
{file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
{file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
{file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
{file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
{file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
{file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
{file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
{file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
{file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
{file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
{file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
{file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
]
[[package]]
name = "mccabe"
version = "0.7.0"
@ -441,6 +772,61 @@ files = [
[package.dependencies]
setuptools = "*"
[[package]]
name = "orjson"
version = "3.9.1"
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
optional = false
python-versions = ">=3.7"
files = [
{file = "orjson-3.9.1-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4434b7b786fdc394b95d029fb99949d7c2b05bbd4bf5cb5e3906be96ffeee3b"},
{file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09faf14f74ed47e773fa56833be118e04aa534956f661eb491522970b7478e3b"},
{file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:503eb86a8d53a187fe66aa80c69295a3ca35475804da89a9547e4fce5f803822"},
{file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20f2804b5a1dbd3609c086041bd243519224d47716efd7429db6c03ed28b7cc3"},
{file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fd828e0656615a711c4cc4da70f3cac142e66a6703ba876c20156a14e28e3fa"},
{file = "orjson-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec53d648176f873203b9c700a0abacab33ca1ab595066e9d616f98cdc56f4434"},
{file = "orjson-3.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e186ae76b0d97c505500664193ddf508c13c1e675d9b25f1f4414a7606100da6"},
{file = "orjson-3.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d4edee78503016f4df30aeede0d999b3cb11fb56f47e9db0e487bce0aaca9285"},
{file = "orjson-3.9.1-cp310-none-win_amd64.whl", hash = "sha256:a4cc5d21e68af982d9a2528ac61e604f092c60eed27aef3324969c68f182ec7e"},
{file = "orjson-3.9.1-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:761b6efd33c49de20dd73ce64cc59da62c0dab10aa6015f582680e0663cc792c"},
{file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31229f9d0b8dc2ef7ee7e4393f2e4433a28e16582d4b25afbfccc9d68dc768f8"},
{file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b7ab18d55ecb1de543d452f0a5f8094b52282b916aa4097ac11a4c79f317b86"},
{file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db774344c39041f4801c7dfe03483df9203cbd6c84e601a65908e5552228dd25"},
{file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae47ef8c0fe89c4677db7e9e1fb2093ca6e66c3acbee5442d84d74e727edad5e"},
{file = "orjson-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:103952c21575b9805803c98add2eaecd005580a1e746292ed2ec0d76dd3b9746"},
{file = "orjson-3.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2cb0121e6f2c9da3eddf049b99b95fef0adf8480ea7cb544ce858706cdf916eb"},
{file = "orjson-3.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:24d4ddaa2876e657c0fd32902b5c451fd2afc35159d66a58da7837357044b8c2"},
{file = "orjson-3.9.1-cp311-none-win_amd64.whl", hash = "sha256:0b53b5f72cf536dd8aa4fc4c95e7e09a7adb119f8ff8ee6cc60f735d7740ad6a"},
{file = "orjson-3.9.1-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4b68d01a506242316a07f1d2f29fb0a8b36cee30a7c35076f1ef59dce0890c1"},
{file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9dd4abe6c6fd352f00f4246d85228f6a9847d0cc14f4d54ee553718c225388f"},
{file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e20bca5e13041e31ceba7a09bf142e6d63c8a7467f5a9c974f8c13377c75af2"},
{file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8ae0467d01eb1e4bcffef4486d964bfd1c2e608103e75f7074ed34be5df48cc"},
{file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06f6ab4697fab090517f295915318763a97a12ee8186054adf21c1e6f6abbd3d"},
{file = "orjson-3.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8515867713301fa065c58ec4c9053ba1a22c35113ab4acad555317b8fd802e50"},
{file = "orjson-3.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:393d0697d1dfa18d27d193e980c04fdfb672c87f7765b87952f550521e21b627"},
{file = "orjson-3.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d96747662d3666f79119e5d28c124e7d356c7dc195cd4b09faea4031c9079dc9"},
{file = "orjson-3.9.1-cp37-none-win_amd64.whl", hash = "sha256:6d173d3921dd58a068c88ec22baea7dbc87a137411501618b1292a9d6252318e"},
{file = "orjson-3.9.1-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d1c2b0b4246c992ce2529fc610a446b945f1429445ece1c1f826a234c829a918"},
{file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19f70ba1f441e1c4bb1a581f0baa092e8b3e3ce5b2aac2e1e090f0ac097966da"},
{file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:375d65f002e686212aac42680aed044872c45ee4bc656cf63d4a215137a6124a"},
{file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4751cee4a7b1daeacb90a7f5adf2170ccab893c3ab7c5cea58b45a13f89b30b3"},
{file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d9a2a4b2302d5ebc3695498ebc305c3568e5ad4f3501eb30a6405a32d8af22"},
{file = "orjson-3.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46b4facc32643b2689dfc292c0c463985dac4b6ab504799cf51fc3c6959ed668"},
{file = "orjson-3.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec7c8a0f1bf35da0d5fd14f8956f3b82a9a6918a3c6963d718dfd414d6d3b604"},
{file = "orjson-3.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d3a40b0fbe06ccd4d6a99e523d20b47985655bcada8d1eba485b1b32a43e4904"},
{file = "orjson-3.9.1-cp38-none-win_amd64.whl", hash = "sha256:402f9d3edfec4560a98880224ec10eba4c5f7b4791e4bc0d4f4d8df5faf2a006"},
{file = "orjson-3.9.1-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:49c0d78dcd34626e2e934f1192d7c052b94e0ecadc5f386fd2bda6d2e03dadf5"},
{file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:125f63e56d38393daa0a1a6dc6fedefca16c538614b66ea5997c3bd3af35ef26"},
{file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08927970365d2e1f3ce4894f9ff928a7b865d53f26768f1bbdd85dd4fee3e966"},
{file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9a744e212d4780ecd67f4b6b128b2e727bee1df03e7059cddb2dfe1083e7dc4"},
{file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d1dbf36db7240c61eec98c8d21545d671bce70be0730deb2c0d772e06b71af3"},
{file = "orjson-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a1e384626f76b66df615f7bb622a79a25c166d08c5d2151ffd41f24c4cc104"},
{file = "orjson-3.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:15d28872fb055bf17ffca913826e618af61b2f689d2b170f72ecae1a86f80d52"},
{file = "orjson-3.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e4d905338f9ef32c67566929dfbfbb23cc80287af8a2c38930fb0eda3d40b76"},
{file = "orjson-3.9.1-cp39-none-win_amd64.whl", hash = "sha256:48a27da6c7306965846565cc385611d03382bbd84120008653aa2f6741e2105d"},
{file = "orjson-3.9.1.tar.gz", hash = "sha256:db373a25ec4a4fccf8186f9a72a1b3442837e40807a736a815ab42481e83b7d0"},
]
[[package]]
name = "packaging"
version = "23.1"
@ -452,6 +838,30 @@ files = [
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
]
[[package]]
name = "paho-mqtt"
version = "1.6.1"
description = "MQTT version 5.0/3.1.1 client class"
optional = false
python-versions = "*"
files = [
{file = "paho-mqtt-1.6.1.tar.gz", hash = "sha256:2a8291c81623aec00372b5a85558a372c747cbca8e9934dfe218638b8eefc26f"},
]
[package.extras]
proxy = ["PySocks"]
[[package]]
name = "pastel"
version = "0.2.1"
description = "Bring colors to your terminal."
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
{file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"},
{file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"},
]
[[package]]
name = "pathspec"
version = "0.11.1"
@ -478,6 +888,24 @@ files = [
docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
[[package]]
name = "poethepoet"
version = "0.20.0"
description = "A task runner that works well with poetry."
optional = false
python-versions = ">=3.8"
files = [
{file = "poethepoet-0.20.0-py3-none-any.whl", hash = "sha256:cb37be15f3895ccc65ddf188c2e3d8fb79e26cc9d469a6098cb1c6f994659f6f"},
{file = "poethepoet-0.20.0.tar.gz", hash = "sha256:ca5a2a955f52dfb0a53fad3c989ef0b69ce3d5ec0f6bfa9b1da1f9e32d262e20"},
]
[package.dependencies]
pastel = ">=0.2.1,<0.3.0"
tomli = ">=1.2.2"
[package.extras]
poetry-plugin = ["poetry (>=1.0,<2.0)"]
[[package]]
name = "pre-commit"
version = "3.3.2"
@ -496,6 +924,20 @@ nodeenv = ">=0.11.1"
pyyaml = ">=5.1"
virtualenv = ">=20.10.0"
[[package]]
name = "prompt-toolkit"
version = "3.0.38"
description = "Library for building powerful interactive command lines in Python"
optional = false
python-versions = ">=3.7.0"
files = [
{file = "prompt_toolkit-3.0.38-py3-none-any.whl", hash = "sha256:45ea77a2f7c60418850331366c81cf6b5b9cf4c7fd34616f733c5427e6abbb1f"},
{file = "prompt_toolkit-3.0.38.tar.gz", hash = "sha256:23ac5d50538a9a38c8bde05fecb47d0b403ecd0662857a86f886f798563d5b9b"},
]
[package.dependencies]
wcwidth = "*"
[[package]]
name = "psycopg"
version = "3.1.9"
@ -592,6 +1034,23 @@ files = [
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
]
[[package]]
name = "questionary"
version = "1.10.0"
description = "Python library to build pretty command line user prompts ⭐️"
optional = false
python-versions = ">=3.6,<4.0"
files = [
{file = "questionary-1.10.0-py3-none-any.whl", hash = "sha256:fecfcc8cca110fda9d561cb83f1e97ecbb93c613ff857f655818839dac74ce90"},
{file = "questionary-1.10.0.tar.gz", hash = "sha256:600d3aefecce26d48d97eee936fdb66e4bc27f934c3ab6dd1e292c4f43946d90"},
]
[package.dependencies]
prompt_toolkit = ">=2.0,<4.0"
[package.extras]
docs = ["Sphinx (>=3.3,<4.0)", "sphinx-autobuild (>=2020.9.1,<2021.0.0)", "sphinx-autodoc-typehints (>=1.11.1,<2.0.0)", "sphinx-copybutton (>=0.3.1,<0.4.0)", "sphinx-rtd-theme (>=0.5.0,<0.6.0)"]
[[package]]
name = "setuptools"
version = "67.8.0"
@ -608,6 +1067,28 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "shortuuid"
version = "1.0.11"
description = "A generator library for concise, unambiguous and URL-safe UUIDs."
optional = false
python-versions = ">=3.5"
files = [
{file = "shortuuid-1.0.11-py3-none-any.whl", hash = "sha256:27ea8f28b1bd0bf8f15057a3ece57275d2059d2b0bb02854f02189962c13b6aa"},
{file = "shortuuid-1.0.11.tar.gz", hash = "sha256:fc75f2615914815a8e4cb1501b3a513745cb66ef0fd5fc6fb9f8c3fa3481f789"},
]
[[package]]
name = "soupsieve"
version = "2.4.1"
description = "A modern CSS selector implementation for Beautiful Soup."
optional = false
python-versions = ">=3.7"
files = [
{file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"},
{file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"},
]
[[package]]
name = "sqlparse"
version = "0.4.4"
@ -624,6 +1105,31 @@ dev = ["build", "flake8"]
doc = ["sphinx"]
test = ["pytest", "pytest-cov"]
[[package]]
name = "termcolor"
version = "2.3.0"
description = "ANSI color formatting for output in terminal"
optional = false
python-versions = ">=3.7"
files = [
{file = "termcolor-2.3.0-py3-none-any.whl", hash = "sha256:3afb05607b89aed0ffe25202399ee0867ad4d3cb4180d98aaf8eefa6a5f7d475"},
{file = "termcolor-2.3.0.tar.gz", hash = "sha256:b5b08f68937f138fe92f6c089b99f1e2da0ae56c52b78bf7075fd95420fd9a5a"},
]
[package.extras]
tests = ["pytest", "pytest-cov"]
[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "tomlkit"
version = "0.11.8"
@ -635,6 +1141,17 @@ files = [
{file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"},
]
[[package]]
name = "types-paho-mqtt"
version = "1.6.0.6"
description = "Typing stubs for paho-mqtt"
optional = false
python-versions = "*"
files = [
{file = "types-paho-mqtt-1.6.0.6.tar.gz", hash = "sha256:c2c263ee33010b23b2c53c1a6c4b4515ba6f94e8fa391e969c0e8cdd0256de49"},
{file = "types_paho_mqtt-1.6.0.6-py3-none-any.whl", hash = "sha256:c1314b3571fe7699f5e545f83c860a9a1edb885237649afe243dd0aca2f0d725"},
]
[[package]]
name = "types-pytz"
version = "2023.3.0.0"
@ -699,6 +1216,17 @@ platformdirs = ">=3.2,<4"
docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"]
test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"]
[[package]]
name = "wcwidth"
version = "0.2.6"
description = "Measures the displayed width of unicode strings in a terminal"
optional = false
python-versions = "*"
files = [
{file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
{file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
]
[[package]]
name = "wrapt"
version = "1.15.0"
@ -783,7 +1311,22 @@ files = [
{file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
]
[[package]]
name = "zipp"
version = "3.15.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.7"
files = [
{file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"},
{file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
content-hash = "883d289b797f752997bbd26da35284563752da2a34b6139c4fc3864862b1b082"
content-hash = "71d18a63fce9219d20db5d34b3060998e373bdf448cec0377b9f49b54711e709"

View File

@ -4,12 +4,14 @@ version = "0.1.0"
description = "A Django web app to post messages on my Pimoroni Galactic unicorn via MQTT"
authors = ["Flavien Henrion <flavien@coincoinmail.fr>"]
readme = "README.md"
packages = [{include = "unicorn_post"}]
[tool.poetry.dependencies]
python = "^3.11"
Django = "^4.2.1"
psycopg = "^3.1.9"
django-tailwind = "^3.5.0"
django-unicorn = {extras = ["minify"], version = "^0.51.1"}
paho-mqtt = "^1.6.1"
[tool.poetry.group.dev.dependencies]
black = "^23.3.0"
@ -18,6 +20,9 @@ pylint = "^2.17.4"
pre-commit = "^3.3.2"
django-stubs = {extras = ["compatible-mypy"], version = "^4.2.0"}
coverage = "^7.2.7"
types-paho-mqtt = "^1.6.0.6"
poethepoet = "^0.20.0"
commitizen = "^3.3.0"
[build-system]
requires = ["poetry-core"]
@ -25,6 +30,35 @@ build-backend = "poetry.core.masonry.api"
[tool.mypy]
plugins = ["mypy_django_plugin.main"]
mypy_path = 'unicorn_post'
[[tool.mypy.overrides]]
module = "django_unicorn.components"
ignore_missing_imports = true
[tool.django-stubs]
django_settings_module = "unicorn_post.unicorn_post.settings"
django_settings_module = "unicorn_post.settings"
[tool.pylint.messages_control]
disable = [
"missing-docstring",
"import-outside-toplevel",
"invalid-name",
"no-member",
"too-many-ancestors",
"consider-using-from-import"
]
[tool.poe.tasks]
format = "black unicorn_post"
check_format = "black --check unicorn_post"
linter = "pylint --recursive y unicorn_post"
check_types = "mypy unicorn_post"
check = ["check_format", "linter", "check_types"]
test = "python unicorn_post/manage.py test unicorn_post/"
[tool.commitizen]
version = "0.1.0"
version_files = [
"pyproject.toml:version"
]

View File

@ -1,3 +1,5 @@
# from django.contrib import admin
from django.contrib import admin
from .models import Message
# Register your models here.
admin.site.register(Message)

View File

View File

@ -0,0 +1,67 @@
import logging
import json
from django.utils import timezone
from django_unicorn.components import UnicornView
from post.models import Message
from post.mqtt import publish
logger = logging.getLogger(__name__)
class MessageView(UnicornView):
content = ""
background_color = "black"
text_color = "white"
alarm = False
rgb_colors = {
"red": (255, 0, 0),
"green": (0, 255, 0),
"blue": (0, 0, 255),
"yellow": (255, 255, 0),
"orange": (237, 127, 16),
"purple": (102, 0, 153),
"pink": (253, 108, 158),
"white": (255, 255, 255),
"black": (0, 0, 0),
"grey": (128, 128, 128),
"brown": (88, 41, 0),
"cyan": (0, 255, 255),
"magenta": (255, 0, 255),
"olive": (128, 128, 0),
"teal": (0, 142, 142),
}
def author_messages(self):
return Message.objects.filter(author=self.request.user).order_by("-send_date")[
:10
]
def resetForm(self):
self.content = ""
self.background_color = "black"
self.text_color = "white"
self.alarm = False
def send_message(self):
if self.content != "":
logger.warning(
"send message: %s, %s, %s, %s",
self.content,
self.background_color,
self.text_color,
self.alarm,
)
payload = {
"text": self.content,
"background_colour": self.background_color,
"message_colour": self.text_color,
"alarm": self.alarm,
}
publish("unicorn/messages", json.dumps(payload))
Message.objects.create(
content=self.content, author=self.request.user, send_date=timezone.now()
)
self.resetForm()

View File

@ -0,0 +1,39 @@
# Generated by Django 4.2.1 on 2023-06-04 19:48
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Message",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("content", models.CharField(max_length=400)),
("send_date", models.DateTimeField(verbose_name="sending date")),
(
"author_id",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 4.2.1 on 2023-06-04 19:50
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("post", "0001_initial"),
]
operations = [
migrations.RenameField(
model_name="message",
old_name="author_id",
new_name="author",
),
]

View File

@ -1,3 +1,21 @@
# from django.db import models
from django.db import models
from django.conf import settings
# Create your models here.
class Message(models.Model):
content: models.CharField = models.CharField(max_length=400)
author: models.ForeignKey = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE
)
send_date: models.DateTimeField = models.DateTimeField("sending date")
@property
def author_name(self):
return self.author.username
@property
def fmt_send_date(self):
return self.send_date.strftime("%d/%m/%Y %H:%M")
def __str__(self):
return f"{self.fmt_send_date} - {self.author_name}: {self.content}"

12
unicorn_post/post/mqtt.py Normal file
View File

@ -0,0 +1,12 @@
import paho.mqtt.client as mq
import unicorn_post.settings as settings
mqtt = mq.Client("restMQTT")
if "USERNAME" in settings.MQTT and "PASSWORD" in settings.MQTT:
mqtt.username_pw_set(settings.MQTT["USERNAME"], settings.MQTT["PASSWORD"])
def publish(topic, payload):
mqtt.connect(settings.MQTT["HOST"], int(settings.MQTT["PORT"]), 15)
mqtt.publish(topic, payload)

View File

@ -0,0 +1,25 @@
{% load static tailwind_tags %}
{% load unicorn %}
<!DOCTYPE html>
<html lang="en" class="h-full bg-gray-100 dark:bg-gray-900">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>✨🦄✉️ Galactic Unicorn Post</title>
<meta name="description" content="✨🦄✉️" />
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.1/dist/cdn.min.js"></script>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%2210 0 100 100%22><text y=%22.90em%22 font-size=%2290%22>🦄</text></svg>">
{% tailwind_css %}
{% unicorn_scripts %}
</head>
<body class="h-full">
{% block content %}
{% endblock %}
</body>
<footer class="dark:text-gray-300 text-gray-500 pb-3 ml-3">
<p>Made by <a href="https://cyberduck.blog" class="font-medium dark:text-gray-100 text-gray-600 hover:underline">cyberduck</a> - <a href="https://coincoingit.fr/flavien/unicorn_post" class="font-medium dark:text-gray-100 text-gray-600 hover:underline">source code</a></p>
</footer>
</html>

View File

@ -0,0 +1,14 @@
{% extends 'base.html' %}
{% load unicorn %}
{% block content %}
<!-- Typography-->
<div class="flex min-h-full flex-col px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-sm py-8">
<h1 class="mx-auto w-auto text-center text-6xl text-gray-900 dark:text-white">Galactic ✨ Unicorn 🦄 Post ✉️</h1>
</div>
<div class="sm:mx-auto sm:w-full sm:max-w-lg">
{% unicorn 'message' key='messageKey' %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,38 @@
{% extends 'base.html' %}
{% block content %}
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
<h1 class="mx-auto w-auto text-center text-6xl text-gray-900 dark:text-white">Galactic ✨ Unicorn 🦄 Post ✉️</h1>
<h2 class="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900 dark:text-white">⚠️ Only for cats 🐈 and ducks 🦆</h2>
{% if error_message %}<p class="mt-10 text-center text-gray-500 dark:text-gray-400 font-semibold">{{ error_message }}</p>{% endif %}
</div>
<div class="my-6 sm:mx-auto sm:w-full sm:max-w-sm">
<form class="space-y-6" action="" method="POST">
{% csrf_token %}
<div>
<label for="username" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Username</label>
<div class="mt-2">
<input id="username" name="login" type="text" autocomplete="username" required class="block w-full rounded-md border-0 dark:bg-white/5 py-1.5 text-gray-900 dark:text-white shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-white/10 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 dark:focus:ring-indigo-500 sm:text-sm sm:leading-6">
</div>
</div>
<div>
<div class="flex items-center justify-between">
<label for="password" class="block text-sm font-medium leading-6 text-gray-900 dark:text-white">Password</label>
<div class="text-sm">
</div>
</div>
<div class="mt-2">
<input id="password" name="password" type="password" autocomplete="current-password" required class="block w-full rounded-md border-0 dark:bg-white/5 py-1.5 text-gray-900 dark:text-white shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-white/10 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 dark:focus:ring-indigo-500 sm:text-sm sm:leading-6">
</div>
</div>
<div>
<button type="submit" class="flex w-full justify-center mt-10 rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Sign in</button>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,287 @@
<div>
<div
x-data="{
background_color: '{{ background_color }}',
text_color: '{{ text_color }}',
color_choices: [
{% for name, channels in rgb_colors.items %}
{ name: '{{ name }}', channels: [ {{ channels.0 }}, {{ channels.1 }}, {{ channels.2 }}]},
{% endfor %}
],
alarm: {{ alarm|lower }},
colorStyle(name) {
channels = this.color_choices.find(color => color.name === name).channels
return `background-color: rgb(${channels[0]}, ${channels[1]}, ${channels[2]});`
},
resetForm() {
this.background_color = '{{ background_color }}'
this.text_color = '{{ text_color }}'
this.alarm = {{ alarm|lower }}
$refs.content.value = ''
}
}"
class="my-8 relative"
>
<div class="overflow-hidden rounded-lg border border-gray-300 dark:border-white/10 shadow-sm focus-within:border-indigo-500 focus-within:ring-1 focus-within:ring-indigo-500">
<label for="content" class="sr-only">Content</label>
<input
x-ref="content"
x-on:keyup.enter="
Unicorn.trigger('message', 'background_color');
Unicorn.trigger('message', 'text_color');
Unicorn.trigger('message', 'alarm');
resetForm();
"
unicorn:keyup.enter="send_message"
unicorn:partial="message-list"
unicorn:model.defer="content"
type="text"
class="w-full py-2.5 border-0 py-0 text-gray-900 dark:text-white placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6 dark:bg-white/5"
placeholder="Write a message..."
/>
<!-- Spacer element to match the height of the toolbar -->
<div aria-hidden="true" class="bg-white dark:bg-white/5">
<div class="h-px"></div>
<div class="py-2">
<div class="py-px">
<div class="h-9"></div>
</div>
</div>
</div>
</div>
<div class="absolute inset-x-px bottom-0 flex items-center justify-between border-t border-gray-200 dark:border-white/10 px-2 py-2 sm:px-3">
<div class="flex flex-nowrap">
<div class="flex flex-nowrap space-x-3">
<div class="flex-shrink-0">
<label id="background-label" class="sr-only">Background color select</label>
<div
x-data="{
open: false,
toggle() {
if (this.open) {
return this.close()
}
this.$refs.background_button.focus()
this.open = true
},
close(focusAfter) {
if (! this.open) return
this.open = false
focusAfter && focusAfter.focus()
}
}"
x-on:keydown.escape.prevent.stop="close($refs.background_button)"
x-on:focusin.window="! $refs.background_panel.contains($event.target) && close()"
x-id="['dropdown-button']"
class="relative"
>
<button
x-ref="background_button"
x-on:click="toggle()"
:aria-expanded="open"
:aria-controls="$id('dropdown-button')"
type="button"
class="relative inline-flex items-center whitespace-nowrap rounded-full bg-gray-50 dark:bg-white/5 px-2 py-2 text-sm font-medium text-gray-500 dark:text-white hover:bg-gray-100 dark:hover:bg-white/10 sm:px-3"
aria-haspopup="listbox"
aria-labelledby="background-label"
>
<span class="flex items-center">
<span aria-label="Color" class="inline-block h-2 w-2 flex-shrink-0 rounded-full" :style="colorStyle(background_color)" />
<span class="hidden truncate sm:ml-2 sm:block mr-1">background</span>
<input
x-model="background_color"
unicorn:model.defer="background_color"
unicorn:key="background_color"
type="text"
class="hidden"
/>
</span>
</button>
<ul
x-ref="background_panel"
x-show="open"
x-transition:enter=""
x-transition:enter-start=""
x-transition:enter-end=""
x-transition:leave="transition ease-in duration-100"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
x-on:click.outside="close($refs.background_button)"
:id="$id('dropdown-button')"
class="absolute left-0 z-10 mt-1 max-h-56 overflow-auto rounded-lg bg-white dark:bg-gray-800 py-3 text-base shadow ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
tabindex="-1"
role="listbox"
aria-labelledby="background-label"
>
<template x-for="color in color_choices">
<li
x-on:click="background_color = color.name; open = false"
class="relative select-none px-3 py-2 text-gray-900 dark:text-white cursor-pointer"
role="option"
>
<div class="flex items-center">
<span aria-label="Color" class="inline-block h-2 w-2 flex-shrink-0 rounded-full" :style="colorStyle(color.name)" />
<span x-text="color.name" class="ml-3 mr-1 block truncate font-medium" />
</div>
</li>
</template>
</ul>
</div>
</div>
<div class="flex-shrink-0">
<label id="text-label" class="sr-only">Text color select</label>
<div
x-data="{
open: false,
toggle() {
if (this.open) {
return this.close()
}
this.$refs.text_button.focus()
this.open = true
},
close(focusAfter) {
if (! this.open) return
this.open = false
focusAfter && focusAfter.focus()
},
}"
x-on:keydown.escape.prevent.stop="close($refs.text_button)"
x-on:focusin.window="! $refs.text_panel.contains($event.target) && close()"
x-id="['dropdown-button']"
class="relative"
>
<button
x-ref="text_button"
x-on:click="toggle()"
:aria-expanded="open"
:aria-controls="$id('dropdown-button')"
type="button"
class="relative inline-flex items-center whitespace-nowrap rounded-full bg-gray-50 dark:bg-white/5 px-2 py-2 text-sm font-medium text-gray-500 dark:text-white hover:bg-gray-100 dark:hover:bg-white/10 sm:px-3"
aria-haspopup="listbox"
aria-labelledby="text-label"
>
<span class="flex items-center">
<span aria-label="Online" class="inline-block h-2 w-2 flex-shrink-0 rounded-full" :style="colorStyle(text_color)" />
<span class="hidden truncate sm:ml-2 sm:block mr-1">text</span>
<input
x-model="text_color"
unicorn:model.defer="text_color"
unicorn:key="text_color"
type="text"
class="hidden"
/>
</span>
</button>
<ul
x-ref="text_panel"
x-show="open"
x-transition:enter=""
x-transition:enter-start=""
x-transition:enter-end=""
x-transition:leave="transition ease-in duration-100"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
x-on:click.outside="close($refs.text_button)"
:id="$id('dropdown-button')"
class="absolute left-0 z-10 mt-1 max-h-56 overflow-auto rounded-lg bg-white dark:bg-gray-800 py-3 text-base shadow ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
tabindex="-1"
role="listbox"
aria-labelledby="text-label"
>
<template x-for="color in color_choices">
<li
x-on:click="text_color = color.name; open = false"
class="relative select-none px-3 py-2 text-gray-900 dark:text-white cursor-pointer"
role="option"
>
<div class="flex items-center">
<span aria-label="Color" class="inline-block h-2 w-2 flex-shrink-0 rounded-full" :style="colorStyle(color.name)" />
<span x-text="color.name" class="ml-3 mr-1 block truncate font-medium" />
</div>
</li>
</template>
</ul>
</div>
</div>
<div class="flex-shrink-0 my-auto">
<label id="alarm-label" class="sr-only">Alarm trigger</label>
<div class="flex items-center">
<button
x-on:click="alarm = !alarm"
type="button"
:class="alarm ? 'bg-indigo-600' : 'bg-gray-200 dark:bg-white/5'"
class="relative inline-flex h-6 w-11 flex-shrink-0 rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
role="switch"
aria-checked="false"
aria-labelledby="alarm-label"
>
<span
aria-hidden="true"
:class="alarm ? 'translate-x-5 dark:bg-gray-800' : 'translate-x-0 dark:bg-white/10'"
class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
/>
<input
x-model="alarm"
unicorn:model.defer="alarm"
unicorn:key="alarm"
type="checkbox"
class="hidden"
/>
</button>
<span class="ml-3 text-gray-900 dark:text-white">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.114 5.636a9 9 0 010 12.728M16.463 8.288a5.25 5.25 0 010 7.424M6.75 8.25l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 012.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75z" />
</svg>
</span>
</div>
</div>
</div>
</div>
<div class="flex-shrink-0">
<button
x-on:click="
Unicorn.trigger('message', 'background_color');
Unicorn.trigger('message', 'text_color');
Unicorn.trigger('message', 'alarm');
resetForm();
"
unicorn:click="send_message"
unicorn:partial="message-list"
class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Send
</button>
</div>
</div>
</div>
<ul id="message-list" role="list" class="divide-y divide-gray-100 dark:divide-gray-800 overflow-hidden bg-white dark:bg-white/5 shadow-sm ring-1 ring-gray-900/5 dark:ring-white/10 sm:rounded-xl">
{% for message in author_messages %}
<li class="relative flex justify-between gap-x-6 px-4 py-5 sm:px-6">
<div class="flex gap-x-4 truncate">
<div class="min-w-0 flex-auto">
<p class="text-sm font-semibold leading-6 text-gray-900 dark:text-white">
<span class="absolute inset-x-0 -top-px bottom-0" />
{{ message.author }}
</p>
<p class="mt-1 flex text-xs leading-5 text-gray-500">
<p class="relative text-gray-500 truncate">{{ message.content }}</p>
</p>
</div>
</div>
<div class="hidden sm:flex sm:flex-col sm:items-end">
<p class="text-xs leading-5 text-gray-500">{{ message.fmt_send_date }}</p>
</div>
</li>
{% endfor %}
</ul>
</div>

View File

@ -0,0 +1,9 @@
from django.urls import path
from . import views
app_name = "post"
urlpatterns = [
path("", views.IndexView.as_view(), name="index"),
path("login/", views.login_view, name="login"),
]

View File

@ -1,3 +1,26 @@
# from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.contrib.auth import authenticate, login
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
# Create your views here.
class IndexView(LoginRequiredMixin, generic.ListView):
template_name = "index.html"
login_url = "/login/"
redirect_field_name = ""
def get_queryset(self):
pass
def login_view(request):
if request.method == "POST":
username = request.POST["login"]
password = request.POST["password"]
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return HttpResponseRedirect("/")
return render(request, "login.html", {"error_message": "Invalid login"})
return render(request, "login.html", {})

View File

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class ThemeConfig(AppConfig):
name = "theme"

View File

@ -0,0 +1 @@
node_modules

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
{
"name": "theme",
"version": "3.5.0",
"description": "",
"scripts": {
"start": "npm run dev",
"build": "npm run build:clean && npm run build:tailwind",
"build:clean": "rimraf ../static/css/dist",
"build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css --minify",
"dev": "cross-env NODE_ENV=development tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css -w",
"tailwindcss": "node ./node_modules/tailwindcss/lib/cli.js"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.2",
"cross-env": "^7.0.3",
"postcss": "^8.4.14",
"postcss-import": "^15.1.0",
"postcss-nested": "^6.0.0",
"postcss-simple-vars": "^7.0.1",
"rimraf": "^4.1.2",
"tailwindcss": "^3.2.7"
}
}

View File

@ -0,0 +1,7 @@
module.exports = {
plugins: {
"postcss-import": {},
"postcss-simple-vars": {},
"postcss-nested": {}
},
}

View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -0,0 +1,58 @@
/**
* This is a minimal config.
*
* If you need the full config, get it from here:
* https://unpkg.com/browse/tailwindcss@latest/stubs/defaultConfig.stub.js
*/
module.exports = {
content: [
/**
* HTML. Paths to Django template files that will contain Tailwind CSS classes.
*/
/* Templates within theme app (<tailwind_app_name>/templates), e.g. base.html. */
'../templates/**/*.html',
/*
* Main templates directory of the project (BASE_DIR/templates).
* Adjust the following line to match your project structure.
*/
'../../templates/**/*.html',
/*
* Templates in other django apps (BASE_DIR/<any_app_name>/templates).
* Adjust the following line to match your project structure.
*/
'../../**/templates/**/*.html',
/**
* JS: If you use Tailwind CSS in JavaScript, uncomment the following lines and make sure
* patterns match your project structure.
*/
/* JS 1: Ignore any JavaScript in node_modules folder. */
// '!../../**/node_modules',
/* JS 2: Process all JavaScript files in the project. */
// '../../**/*.js',
/**
* Python: If you use Tailwind CSS classes in Python, uncomment the following line
* and make sure the pattern below matches your project structure.
*/
// '../../**/*.py'
],
theme: {
extend: {},
},
plugins: [
/**
* '@tailwindcss/forms' is the forms plugin that provides a minimal styling
* for forms. If you don't like it or have own styling for forms,
* comment the line below to disable '@tailwindcss/forms'.
*/
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
require('@tailwindcss/line-clamp'),
require('@tailwindcss/aspect-ratio'),
],
}

View File

@ -32,12 +32,17 @@ ALLOWED_HOSTS: List[str] = []
# Application definition
INSTALLED_APPS = [
"post",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django_unicorn",
"tailwind",
"theme",
"django_browser_reload",
]
MIDDLEWARE = [
@ -48,6 +53,7 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django_browser_reload.middleware.BrowserReloadMiddleware",
]
ROOT_URLCONF = "unicorn_post.urls"
@ -76,8 +82,12 @@ WSGI_APPLICATION = "unicorn_post.wsgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
"ENGINE": "django.db.backends.postgresql",
"NAME": "unicorn_post_db",
"USER": "galactic",
"PASSWORD": "unicorn",
"HOST": "postgres",
"PORT": "5432",
}
}
@ -106,7 +116,7 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
TIME_ZONE = "Europe/Paris"
USE_I18N = True
@ -122,3 +132,30 @@ STATIC_URL = "static/"
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
TAILWIND_APP_NAME = "theme"
INTERNAL_IPS = [
"127.0.0.1",
]
UNICORN = {
"APPS": [
"post",
],
"CACHE_ALIAS": "default",
"MINIFY_HTML": True,
"MINIFIED": True,
"RELOAD_SCRIPT_ELEMENTS": False,
"SERIAL": {
"ENABLED": False,
"TIMEOUT": 60,
},
"SCRIPT_LOCATION": "after",
}
MQTT: dict[str, str] = {
"HOST": "192.168.1.4",
"PORT": "1883",
"USERNAME": "flavien",
"PASSWORD": "T0urn3v1s",
}

View File

@ -15,8 +15,11 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("post.urls")),
path("__reload__/", include("django_browser_reload.urls")),
path("unicorn/", include("django_unicorn.urls")),
]