Bolt up a WSGI server shim; tapping on verification
This commit is contained in:
parent
883c74bf62
commit
b981e1255e
13 changed files with 140 additions and 37 deletions
6
projects/cherry-shim/BUILD
Normal file
6
projects/cherry-shim/BUILD
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
py_project(
|
||||||
|
name = "cherry-shim",
|
||||||
|
lib_deps = [
|
||||||
|
py_requirement("cherrypy"),
|
||||||
|
]
|
||||||
|
)
|
28
projects/cherry-shim/src/python/cherry_shim.py
Normal file
28
projects/cherry-shim/src/python/cherry_shim.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Import CherryPy
|
||||||
|
import cherrypy
|
||||||
|
|
||||||
|
|
||||||
|
def shim(app):
|
||||||
|
# Mount the application
|
||||||
|
cherrypy.tree.graft(app, "/")
|
||||||
|
|
||||||
|
# Unsubscribe the default server
|
||||||
|
cherrypy.server.unsubscribe()
|
||||||
|
|
||||||
|
# Instantiate a new server object
|
||||||
|
server = cherrypy._cpserver.Server()
|
||||||
|
|
||||||
|
def _run(host="0.0.0.0", port=8080, pool_size=16):
|
||||||
|
# Configure the server object
|
||||||
|
server.socket_host = host
|
||||||
|
server.socket_port = port
|
||||||
|
server.thread_pool = pool_size
|
||||||
|
server.subscribe()
|
||||||
|
cherrypy.engine.start()
|
||||||
|
cherrypy.engine.block()
|
||||||
|
|
||||||
|
server.run = _run
|
||||||
|
|
||||||
|
return server
|
|
@ -4,6 +4,7 @@ py_project(
|
||||||
main_deps = [
|
main_deps = [
|
||||||
"//projects/anosql",
|
"//projects/anosql",
|
||||||
"//projects/anosql-migrations",
|
"//projects/anosql-migrations",
|
||||||
|
"//projects/cherry-shim",
|
||||||
py_requirement("click"),
|
py_requirement("click"),
|
||||||
py_requirement("flask"),
|
py_requirement("flask"),
|
||||||
py_requirement("jinja2"),
|
py_requirement("jinja2"),
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
SECRET_KEY = "SgvzxsO5oPBGInmqsyyGQWAJXkS9"
|
|
||||||
UPLOAD_FOLDER = "/home/arrdem/Documents/hobby/programming/source/projects/tentacles/tmp"
|
|
||||||
|
|
||||||
[db]
|
|
||||||
uri = "/home/arrdem/Documents/hobby/programming/source/projects/tentacles/tentacles.sqlite3"
|
|
||||||
|
|
||||||
[[users]]
|
|
||||||
email = "root@tirefireind.us"
|
|
||||||
group_id = 0
|
|
||||||
status_id = 1
|
|
|
@ -8,6 +8,8 @@ import tomllib
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from flask import Flask, request
|
from flask import Flask, request
|
||||||
|
|
||||||
|
from cherry_shim import shim
|
||||||
from tentacles.blueprints import (
|
from tentacles.blueprints import (
|
||||||
api,
|
api,
|
||||||
file_ui,
|
file_ui,
|
||||||
|
@ -102,10 +104,11 @@ def serve(hostname: str, port: int, config: Path):
|
||||||
|
|
||||||
# Shove our middleware in there
|
# Shove our middleware in there
|
||||||
app.wsgi_app = custom_ctx(app, app.wsgi_app)
|
app.wsgi_app = custom_ctx(app, app.wsgi_app)
|
||||||
|
cherry = shim(app)
|
||||||
|
|
||||||
# And run the blame thing
|
# And run the blame thing
|
||||||
try:
|
try:
|
||||||
app.run(host=hostname, port=port)
|
cherry.run(host=hostname, port=port)
|
||||||
finally:
|
finally:
|
||||||
shutdown_event.set()
|
shutdown_event.set()
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ class Ctx:
|
||||||
sid: str = None
|
sid: str = None
|
||||||
username: str = None
|
username: str = None
|
||||||
is_admin: bool = None
|
is_admin: bool = None
|
||||||
|
base_url: str = None
|
||||||
|
|
||||||
|
|
||||||
_ctx = ContextVar("tentacles.ctx")
|
_ctx = ContextVar("tentacles.ctx")
|
||||||
|
|
|
@ -14,8 +14,9 @@ CREATE TABLE IF NOT EXISTS user_statuses (
|
||||||
, UNIQUE(name)
|
, UNIQUE(name)
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT OR IGNORE INTO user_statuses (id, name) VALUES (-1, 'disabled');
|
INSERT OR IGNORE INTO user_statuses (id, name) VALUES (-3, 'unapproved');
|
||||||
INSERT OR IGNORE INTO user_statuses (id, name) VALUES (-2, 'unverified');
|
INSERT OR IGNORE INTO user_statuses (id, name) VALUES (-2, 'unverified');
|
||||||
|
INSERT OR IGNORE INTO user_statuses (id, name) VALUES (-1, 'disabled');
|
||||||
INSERT OR IGNORE INTO user_statuses (id, name) VALUES (1, 'enabled');
|
INSERT OR IGNORE INTO user_statuses (id, name) VALUES (1, 'enabled');
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
@ -25,7 +26,9 @@ CREATE TABLE IF NOT EXISTS users (
|
||||||
, email TEXT
|
, email TEXT
|
||||||
, hash TEXT
|
, hash TEXT
|
||||||
, status_id INTEGER
|
, status_id INTEGER
|
||||||
|
, verification_token TEXT DEFAULT (lower(hex(randomblob(32))))
|
||||||
, verified_at TEXT
|
, verified_at TEXT
|
||||||
|
, approved_at TEXT
|
||||||
, enabled_at TEXT
|
, enabled_at TEXT
|
||||||
, FOREIGN KEY(group_id) REFERENCES groups(id)
|
, FOREIGN KEY(group_id) REFERENCES groups(id)
|
||||||
, FOREIGN KEY(status_id) REFERENCES user_statuses(id)
|
, FOREIGN KEY(status_id) REFERENCES user_statuses(id)
|
||||||
|
@ -61,6 +64,7 @@ CREATE TABLE IF NOT EXISTS printers (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||||
, name TEXT
|
, name TEXT
|
||||||
, url TEXT
|
, url TEXT
|
||||||
|
, stream_url TEXT
|
||||||
, api_key TEXT
|
, api_key TEXT
|
||||||
, status_id INTEGER
|
, status_id INTEGER
|
||||||
, last_poll_date TEXT
|
, last_poll_date TEXT
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="{{ base_url }}/static/css/style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="container navbar">
|
||||||
|
<span class="logo">
|
||||||
|
<a class="row" href="/">
|
||||||
|
<img src="{{ base_url }}/static/tentacles.svg" alt="Tentacles">
|
||||||
|
<span class="name color-yellow">Tentacles</span>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container content">
|
||||||
|
<div class="row">
|
||||||
|
<p>
|
||||||
|
Welcome {{ username }}!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Before you can use your account, please confirm your email address by clicking <a href="{{ base_url }}/user/verify?token={{token_id}}">this link</a> or pasting the following text into your browser's navigation bar.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
{{ base_url }}/user/verify?token={{token_id}}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Once your email has been verified, one of our administrators will review and approve your account. Then you can get to printing!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
|
||||||
|
</footer>
|
||||||
|
</html>
|
|
@ -265,7 +265,13 @@ def send_verifications(app, store: Store):
|
||||||
fm.send_message(
|
fm.send_message(
|
||||||
from_addr="root@tirefireind.us",
|
from_addr="root@tirefireind.us",
|
||||||
to_addrs=[user.email],
|
to_addrs=[user.email],
|
||||||
msg=render_template("verification_email.html.j2"),
|
subject="Email verification from tentacles",
|
||||||
|
msg=render_template(
|
||||||
|
"verification_email.html.j2",
|
||||||
|
base_url=app.config.get("base_url"),
|
||||||
|
username=user.username,
|
||||||
|
token_id=user.verification_token,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,7 +286,7 @@ def send_approvals(app, store: Store):
|
||||||
|
|
||||||
|
|
||||||
@corn_job(timedelta(seconds=5))
|
@corn_job(timedelta(seconds=5))
|
||||||
def run_worker(app, db_factory):
|
def run_worker(app: App, db_factory):
|
||||||
with app.app_context(), closing(db_factory(app)) as store:
|
with app.app_context(), closing(db_factory(app)) as store:
|
||||||
poll_printers(app, store)
|
poll_printers(app, store)
|
||||||
assign_jobs(app, store)
|
assign_jobs(app, store)
|
||||||
|
@ -291,7 +297,7 @@ def run_worker(app, db_factory):
|
||||||
send_approvals(app, store)
|
send_approvals(app, store)
|
||||||
|
|
||||||
|
|
||||||
def create_workers(app, db_factory: Callable[[], Store]) -> Event:
|
def create_workers(app, db_factory: Callable[[App], Store]) -> Event:
|
||||||
Thread(target=run_worker, args=[app, db_factory]).start()
|
Thread(target=run_worker, args=[app, db_factory]).start()
|
||||||
|
|
||||||
return SHUTDOWN
|
return SHUTDOWN
|
||||||
|
|
2
tools/python/constraints.in
Normal file
2
tools/python/constraints.in
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# jaraco.text==git+https://github.com/arrdem/jaraco.text.git@0dd8d0b25a93c3fad896f3a92d11caff61ff273d
|
||||||
|
cherrypy==18.8.0
|
|
@ -44,7 +44,7 @@ def py_pytest(name, srcs, deps, main=None, python_version=None, args=None, **kwa
|
||||||
|
|
||||||
deps = sets.to_list(sets.make([
|
deps = sets.to_list(sets.make([
|
||||||
py_requirement("pytest"),
|
py_requirement("pytest"),
|
||||||
py_requirement("pytest-pudb"),
|
# py_requirement("pytest-pudb"),
|
||||||
py_requirement("pytest-cov"),
|
py_requirement("pytest-cov"),
|
||||||
py_requirement("pytest-timeout"),
|
py_requirement("pytest-timeout"),
|
||||||
] + deps))
|
] + deps))
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
-c constraints.in
|
||||||
|
|
||||||
ExifRead
|
ExifRead
|
||||||
aiohttp
|
aiohttp
|
||||||
aiohttp_basicauth
|
aiohttp_basicauth
|
||||||
|
@ -7,6 +9,7 @@ autoflake
|
||||||
beautifulsoup4
|
beautifulsoup4
|
||||||
black
|
black
|
||||||
cachetools
|
cachetools
|
||||||
|
cherrypy
|
||||||
click
|
click
|
||||||
colored
|
colored
|
||||||
flake8
|
flake8
|
||||||
|
@ -40,6 +43,7 @@ redis
|
||||||
requests
|
requests
|
||||||
requests
|
requests
|
||||||
retry
|
retry
|
||||||
|
pip-tools
|
||||||
smbus2
|
smbus2
|
||||||
sphinx
|
sphinx
|
||||||
sphinxcontrib-openapi
|
sphinxcontrib-openapi
|
||||||
|
|
|
@ -5,34 +5,42 @@ alabaster==0.7.13
|
||||||
async-lru==2.0.2
|
async-lru==2.0.2
|
||||||
async-timeout==4.0.2
|
async-timeout==4.0.2
|
||||||
attrs==23.1.0
|
attrs==23.1.0
|
||||||
|
autocommand==2.2.2
|
||||||
autoflake==2.1.1
|
autoflake==2.1.1
|
||||||
Babel==2.12.1
|
Babel==2.12.1
|
||||||
beautifulsoup4==4.12.2
|
beautifulsoup4==4.12.2
|
||||||
black==23.3.0
|
black==23.3.0
|
||||||
blinker==1.6.2
|
blinker==1.6.2
|
||||||
cachetools==5.3.0
|
build==0.10.0
|
||||||
certifi==2022.12.7
|
cachetools==5.3.1
|
||||||
|
certifi==2023.5.7
|
||||||
charset-normalizer==3.1.0
|
charset-normalizer==3.1.0
|
||||||
|
cheroot==10.0.0
|
||||||
|
CherryPy==18.8.0
|
||||||
click==8.1.3
|
click==8.1.3
|
||||||
colored==1.4.4
|
colored==1.4.4
|
||||||
commonmark==0.9.1
|
commonmark==0.9.1
|
||||||
coverage==7.2.2
|
coverage==7.2.7
|
||||||
decorator==5.1.1
|
decorator==5.1.1
|
||||||
deepmerge==1.1.0
|
deepmerge==1.1.0
|
||||||
docutils==0.19
|
docutils==0.20.1
|
||||||
exceptiongroup==1.1.1
|
|
||||||
ExifRead==3.0.0
|
ExifRead==3.0.0
|
||||||
flake8==6.0.0
|
flake8==6.0.0
|
||||||
Flask==2.3.2
|
Flask==2.3.2
|
||||||
frozenlist==1.3.3
|
frozenlist==1.3.3
|
||||||
hypothesis==6.75.5
|
hypothesis==6.75.9
|
||||||
ibis==3.2.0
|
ibis==3.2.0
|
||||||
icmplib==3.0.3
|
icmplib==3.0.3
|
||||||
idna==3.4
|
idna==3.4
|
||||||
imagesize==1.4.1
|
imagesize==1.4.1
|
||||||
|
inflect==6.0.4
|
||||||
iniconfig==2.0.0
|
iniconfig==2.0.0
|
||||||
isort==5.12.0
|
isort==5.12.0
|
||||||
itsdangerous==2.1.2
|
itsdangerous==2.1.2
|
||||||
|
jaraco.collections==4.2.0
|
||||||
|
jaraco.context==4.3.0
|
||||||
|
jaraco.functools==3.7.0
|
||||||
|
jaraco.text @ git+https://github.com/arrdem/jaraco.text.git@0dd8d0b25a93c3fad896f3a92d11caff61ff273d
|
||||||
jedi==0.18.2
|
jedi==0.18.2
|
||||||
Jinja2==3.1.2
|
Jinja2==3.1.2
|
||||||
jsonschema==4.17.3
|
jsonschema==4.17.3
|
||||||
|
@ -43,52 +51,60 @@ libsass==0.22.0
|
||||||
livereload==2.6.3
|
livereload==2.6.3
|
||||||
lxml==4.9.2
|
lxml==4.9.2
|
||||||
Markdown==3.4.3
|
Markdown==3.4.3
|
||||||
MarkupSafe==2.1.2
|
MarkupSafe==2.1.3
|
||||||
mccabe==0.7.0
|
mccabe==0.7.0
|
||||||
meraki==1.33.0
|
meraki==1.33.0
|
||||||
mirakuru==2.5.1
|
mirakuru==2.5.1
|
||||||
mistune==2.0.5
|
mistune==2.0.5
|
||||||
|
more-itertools==9.1.0
|
||||||
multidict==6.0.4
|
multidict==6.0.4
|
||||||
mypy-extensions==1.0.0
|
mypy-extensions==1.0.0
|
||||||
octorest==0.4
|
octorest==0.4
|
||||||
openapi-schema-validator==0.4.4
|
openapi-schema-validator==0.4.4
|
||||||
openapi-spec-validator==0.5.6
|
openapi-spec-validator==0.5.6
|
||||||
packaging==23.0
|
packaging==23.1
|
||||||
parso==0.8.3
|
parso==0.8.3
|
||||||
pathable==0.4.3
|
pathable==0.4.3
|
||||||
pathspec==0.11.1
|
pathspec==0.11.1
|
||||||
picobox==2.2.0
|
picobox==3.0.0
|
||||||
platformdirs==3.2.0
|
pip==23.1.2
|
||||||
|
pip-tools==6.13.0
|
||||||
|
platformdirs==3.5.1
|
||||||
pluggy==1.0.0
|
pluggy==1.0.0
|
||||||
port-for==0.6.3
|
port-for==0.6.3
|
||||||
|
portend==3.1.0
|
||||||
prompt-toolkit==3.0.38
|
prompt-toolkit==3.0.38
|
||||||
proquint==0.2.1
|
proquint==0.2.1
|
||||||
psutil==5.9.4
|
psutil==5.9.5
|
||||||
psycopg==3.1.9
|
psycopg==3.1.9
|
||||||
psycopg2==2.9.6
|
psycopg2==2.9.6
|
||||||
pudb==2022.1.3
|
pudb==2022.1.3
|
||||||
py==1.11.0
|
py==1.11.0
|
||||||
pycodestyle==2.10.0
|
pycodestyle==2.10.0
|
||||||
pycryptodome==3.18.0
|
pycryptodome==3.18.0
|
||||||
|
pydantic==1.10.8
|
||||||
pyflakes==3.0.1
|
pyflakes==3.0.1
|
||||||
Pygments==2.14.0
|
Pygments==2.15.1
|
||||||
|
pyproject_hooks==1.0.0
|
||||||
pyrsistent==0.19.3
|
pyrsistent==0.19.3
|
||||||
pytest==7.2.2
|
pytest==7.3.1
|
||||||
pytest-cov==4.1.0
|
pytest-cov==4.1.0
|
||||||
pytest-postgresql==5.0.0
|
pytest-postgresql==5.0.0
|
||||||
pytest-pudb==0.7.0
|
pytest-pudb==0.7.0
|
||||||
pytest-timeout==2.1.0
|
pytest-timeout==2.1.0
|
||||||
|
pytz==2023.3
|
||||||
PyYAML==6.0
|
PyYAML==6.0
|
||||||
recommonmark==0.7.1
|
recommonmark==0.7.1
|
||||||
redis==4.5.5
|
redis==4.5.5
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
retry==0.9.2
|
retry==0.9.2
|
||||||
rfc3339-validator==0.1.4
|
rfc3339-validator==0.1.4
|
||||||
|
setuptools==67.7.2
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
smbus2==0.4.2
|
smbus2==0.4.2
|
||||||
snowballstemmer==2.2.0
|
snowballstemmer==2.2.0
|
||||||
sortedcontainers==2.4.0
|
sortedcontainers==2.4.0
|
||||||
soupsieve==2.4
|
soupsieve==2.4.1
|
||||||
Sphinx==7.0.1
|
Sphinx==7.0.1
|
||||||
sphinx_mdinclude==0.5.3
|
sphinx_mdinclude==0.5.3
|
||||||
sphinxcontrib-applehelp==1.0.4
|
sphinxcontrib-applehelp==1.0.4
|
||||||
|
@ -100,19 +116,21 @@ sphinxcontrib-openapi==0.8.1
|
||||||
sphinxcontrib-programoutput==0.17
|
sphinxcontrib-programoutput==0.17
|
||||||
sphinxcontrib-qthelp==1.0.3
|
sphinxcontrib-qthelp==1.0.3
|
||||||
sphinxcontrib-serializinghtml==1.1.5
|
sphinxcontrib-serializinghtml==1.1.5
|
||||||
termcolor==2.2.0
|
tempora==5.2.2
|
||||||
|
termcolor==2.3.0
|
||||||
toml==0.10.2
|
toml==0.10.2
|
||||||
tomli==2.0.1
|
tornado==6.3.2
|
||||||
tornado==6.2
|
typing_extensions==4.6.3
|
||||||
typing_extensions==4.5.0
|
|
||||||
unify==0.5
|
unify==0.5
|
||||||
untokenize==0.1.1
|
untokenize==0.1.1
|
||||||
urllib3==1.26.15
|
urllib3==2.0.2
|
||||||
urwid==2.1.2
|
urwid==2.1.2
|
||||||
urwid-readline==0.13
|
urwid-readline==0.13
|
||||||
wcwidth==0.2.6
|
wcwidth==0.2.6
|
||||||
websocket-client==1.5.1
|
websocket-client==1.5.2
|
||||||
Werkzeug==2.3.4
|
Werkzeug==2.3.4
|
||||||
|
wheel==0.40.0
|
||||||
yamllint==1.32.0
|
yamllint==1.32.0
|
||||||
yarl==1.8.2
|
yarl==1.9.2
|
||||||
yaspin==2.3.0
|
yaspin==2.3.0
|
||||||
|
zc.lockfile==3.0.post1
|
||||||
|
|
Loading…
Reference in a new issue