Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
340006ff37 | ||
|
|
86fcdfde27 | ||
|
|
e0b5e05cce | ||
|
|
9f25457b24 | ||
|
|
9895017385 | ||
|
|
7c2b9fb3f4 |
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
# Keep the Python version in sync with Dockerfile.dev
|
# Keep the Python version in sync with the production Dockerfile
|
||||||
FROM python:3.15-slim-trixie
|
FROM python:3.15-slim-trixie
|
||||||
|
|
||||||
ARG USERNAME=dev
|
ARG USERNAME=dev
|
||||||
@@ -7,17 +7,21 @@ ARG USER_GID=$USER_UID
|
|||||||
|
|
||||||
# git + openssh-client: git over the host's forwarded SSH agent
|
# git + openssh-client: git over the host's forwarded SSH agent
|
||||||
# gcc, libc-dev, libpq-dev: build psycopg2 from requirements.txt
|
# gcc, libc-dev, libpq-dev: build psycopg2 from requirements.txt
|
||||||
# postgresql-client, wait-for-it: scripts/db-setup.sh, scripts/psql.sh
|
# postgresql-client, wait-for-it: database scripts
|
||||||
# curl, ca-certificates: Claude Code installer
|
# curl, ca-certificates: Claude Code installer
|
||||||
# vim: personal preferences
|
# vim, bash-completion: personal preferences
|
||||||
RUN apt-get -y update && \
|
RUN apt-get -y update && \
|
||||||
apt-get install --no-install-recommends -y \
|
apt-get install --no-install-recommends -y \
|
||||||
git openssh-client make curl ca-certificates sudo \
|
git openssh-client make curl ca-certificates sudo \
|
||||||
gcc libc-dev libpq-dev \
|
gcc libc-dev libpq-dev \
|
||||||
postgresql-client wait-for-it \
|
postgresql-client wait-for-it \
|
||||||
vim && \
|
vim bash-completion && \
|
||||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Load bash-completion in every interactive shell (e.g. `make <TAB>`). Not in
|
||||||
|
# ~/.bashrc, since the home dir is a volume (see devcontainer.json).
|
||||||
|
RUN echo '. /usr/share/bash-completion/bash_completion' >> /etc/bash.bashrc
|
||||||
|
|
||||||
RUN groupadd --gid $USER_GID $USERNAME && \
|
RUN groupadd --gid $USER_GID $USERNAME && \
|
||||||
useradd --uid $USER_UID --gid $USER_GID -m -s /bin/bash $USERNAME && \
|
useradd --uid $USER_UID --gid $USER_GID -m -s /bin/bash $USERNAME && \
|
||||||
echo "$USERNAME ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME && \
|
echo "$USERNAME ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME && \
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ services:
|
|||||||
- home:/home/dev
|
- home:/home/dev
|
||||||
environment:
|
environment:
|
||||||
- PYTHONPATH=/workspaces/max
|
- PYTHONPATH=/workspaces/max
|
||||||
- FLASK_APP=max.app
|
|
||||||
- FLASK_ENV=development
|
|
||||||
- PGSQL_HOST=postgresql
|
- PGSQL_HOST=postgresql
|
||||||
- PGSQL_PORT=5432
|
- PGSQL_PORT=5432
|
||||||
- PGSQL_USER=max
|
- PGSQL_USER=max
|
||||||
|
|||||||
@@ -13,10 +13,11 @@
|
|||||||
// Bind mounts are resolved by the host's daemon, so they need host paths:
|
// Bind mounts are resolved by the host's daemon, so they need host paths:
|
||||||
// use ${LOCAL_WORKSPACE_FOLDER} instead of paths inside this container.
|
// use ${LOCAL_WORKSPACE_FOLDER} instead of paths inside this container.
|
||||||
"remoteEnv": {
|
"remoteEnv": {
|
||||||
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
|
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}",
|
||||||
|
"LANG": "C.UTF-8"
|
||||||
},
|
},
|
||||||
"postCreateCommand": "pip install -U pip && pip install -U -r requirements.txt -r requirements-dev.txt",
|
"postCreateCommand": "pip install -U pip && pip install -U -r requirements.txt -r requirements-dev.txt",
|
||||||
"forwardPorts": [
|
"forwardPorts": [
|
||||||
8000
|
8757
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
|
log/
|
||||||
+1
-3
@@ -12,11 +12,9 @@ RUN mkdir log
|
|||||||
|
|
||||||
ENV PYTHONPATH=/app/
|
ENV PYTHONPATH=/app/
|
||||||
ENV FLASK_APP=max.app
|
ENV FLASK_APP=max.app
|
||||||
ENV FLASK_ENV=production
|
|
||||||
|
|
||||||
COPY max/ ./max
|
COPY max/ ./max
|
||||||
COPY scripts/entrypoint.sh .
|
COPY scripts/prod/ .
|
||||||
COPY scripts/db-setup.sh .
|
|
||||||
|
|
||||||
ENTRYPOINT ["./entrypoint.sh"]
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
CMD ["gunicorn", "-w", "1", "-b", "0.0.0.0:8000", "max.app:app"]
|
CMD ["gunicorn", "-w", "1", "-b", "0.0.0.0:8000", "max.app:app"]
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
FROM python:3.15-slim-trixie
|
|
||||||
|
|
||||||
RUN apt -y update && apt -y upgrade && \
|
|
||||||
apt install --no-install-recommends -y wait-for-it lsb-release wget gnupg2 gcc libpq-dev libc-dev vim postgresql-client && apt clean all
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY requirements.txt .
|
|
||||||
COPY requirements-dev.txt .
|
|
||||||
RUN pip install -U -r requirements.txt -r requirements-dev.txt
|
|
||||||
|
|
||||||
RUN mkdir log
|
|
||||||
|
|
||||||
ENV PYTHONPATH=/app/
|
|
||||||
ENV FLASK_APP=max.app
|
|
||||||
ENV FLASK_ENV=development
|
|
||||||
|
|
||||||
COPY scripts/* ./
|
|
||||||
|
|
||||||
ENTRYPOINT ["./entrypoint-dev.sh"]
|
|
||||||
CMD ["flask", "run", "--host", "0.0.0.0", "--port", "8000"]
|
|
||||||
@@ -1,36 +1,21 @@
|
|||||||
# DEVELOPMENT SERVER
|
# DEV
|
||||||
|
seed-dev: clear-dev
|
||||||
|
FLASK_APP=max.app FLASK_DEBUG=1 scripts/dev/seed-db.sh
|
||||||
|
|
||||||
seed-dev:
|
clear-dev:
|
||||||
scripts/entrypoint-dev.sh
|
scripts/dev/clear-db.sh
|
||||||
|
|
||||||
build-dev:
|
run-dev:
|
||||||
docker build -t max:dev -f Dockerfile.dev .
|
FLASK_APP=max.app FLASK_DEBUG=1 flask run --host 0.0.0.0 --port 8757
|
||||||
|
|
||||||
run-dev: | build-dev
|
run-dev-as-prod:
|
||||||
# bash -c "trap 'docker-compose -f dc.dev.yml down' EXIT; MAX_COMMAND=\"flask run --host 0.0.0.0 --port 8000\" docker-compose -f dc.dev.yml up --build"
|
mkdir -p log
|
||||||
MAX_COMMAND="flask run --host 0.0.0.0 --port 8000" docker-compose -f dc.dev.yml up
|
FLASK_APP=max.app LOG_DIR=log gunicorn -w 1 -b 0.0.0.0:8757 max.app:app
|
||||||
|
|
||||||
run-bash: | build-dev
|
run-cleanup:
|
||||||
MAX_COMMAND="sleep infinity" docker-compose -f dc.dev.yml up -d
|
scripts/dev/cleanup.sh
|
||||||
docker-compose -f dc.dev.yml exec max "./entrypoint-dev.sh"
|
|
||||||
docker-compose -f dc.dev.yml exec max chown -R $$(id -u $${USER}):$$(id -g $${USER}) /app
|
|
||||||
docker-compose -f dc.dev.yml exec -u $$(id -u $${USER}):$$(id -g $${USER}) max bash || true
|
|
||||||
docker-compose -f dc.dev.yml down
|
|
||||||
|
|
||||||
run-bash-root: | build-dev
|
|
||||||
MAX_COMMAND="sleep infinity" docker-compose -f dc.dev.yml up -d
|
|
||||||
docker-compose -f dc.dev.yml exec max "./entrypoint-dev.sh"
|
|
||||||
docker-compose -f dc.dev.yml exec max bash || true
|
|
||||||
docker-compose -f dc.dev.yml down
|
|
||||||
|
|
||||||
stop-dev:
|
|
||||||
docker-compose -f dc.dev.yml down
|
|
||||||
|
|
||||||
run-cleanup: | build-dev
|
|
||||||
docker run -ti -v `pwd`/max:/app/max --entrypoint="" max-dev ./cleanup.sh
|
|
||||||
|
|
||||||
# PROD
|
# PROD
|
||||||
|
|
||||||
build-prod:
|
build-prod:
|
||||||
docker build -t max:$(shell cat VERSION) .
|
docker build -t max:$(shell cat VERSION) .
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
function test() {
|
function test() {
|
||||||
$.post("http://localhost:8000/user/1/toggle-enabled", null, function () {
|
$.post("http://localhost:8757/user/1/toggle-enabled", null, function () {
|
||||||
console.log("success", arguments);
|
console.log("success", arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<button onclick="test()">Change</button>
|
<button onclick="test()">Change</button>
|
||||||
|
|
||||||
<form action="http://localhost:8000/user/1/toggle-enabled" method="post">
|
<form action="http://localhost:8757/user/1/toggle-enabled" method="post">
|
||||||
<button type="submit">Submit</button>
|
<button type="submit">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
services:
|
|
||||||
max:
|
|
||||||
image: max:dev
|
|
||||||
volumes:
|
|
||||||
- ./max:/app/max
|
|
||||||
depends_on:
|
|
||||||
- postgresql
|
|
||||||
command: $MAX_COMMAND
|
|
||||||
ports:
|
|
||||||
- 8000:8000/tcp
|
|
||||||
environment:
|
|
||||||
- PGSQL_HOST=postgresql
|
|
||||||
- PGSQL_USER=max
|
|
||||||
- PGSQL_PASSWORD=max
|
|
||||||
- PGSQL_NAME=max
|
|
||||||
networks:
|
|
||||||
- postgresql
|
|
||||||
postgresql:
|
|
||||||
image: postgres:18.6
|
|
||||||
environment:
|
|
||||||
- POSTGRES_USER=max
|
|
||||||
- POSTGRES_PASSWORD=max
|
|
||||||
- POSTGRES_DB=max
|
|
||||||
networks:
|
|
||||||
- postgresql
|
|
||||||
networks:
|
|
||||||
postgresql:
|
|
||||||
+1
-37
@@ -1,8 +1,5 @@
|
|||||||
import base64
|
import base64
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
from logging.config import dictConfig
|
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from werkzeug.routing import Rule as WerkzeugRule
|
from werkzeug.routing import Rule as WerkzeugRule
|
||||||
@@ -11,6 +8,7 @@ from .auth import AuthMiddleware, init as init_auth
|
|||||||
from .cli import register_cli
|
from .cli import register_cli
|
||||||
from .csrf import CsrfMiddleware
|
from .csrf import CsrfMiddleware
|
||||||
from .db import database
|
from .db import database
|
||||||
|
from .log import init_logging
|
||||||
from .middlewares import (
|
from .middlewares import (
|
||||||
ExceptionMiddleware,
|
ExceptionMiddleware,
|
||||||
I18NMiddleware,
|
I18NMiddleware,
|
||||||
@@ -27,40 +25,6 @@ class Rule(WerkzeugRule):
|
|||||||
super().__init__(*args, **kwargs) # do not set methods
|
super().__init__(*args, **kwargs) # do not set methods
|
||||||
|
|
||||||
|
|
||||||
def init_logging(app):
|
|
||||||
dictConfig(
|
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"formatters": {
|
|
||||||
"default": {"format": "[%(asctime)s] [%(levelname)s]: %(message)s"}
|
|
||||||
},
|
|
||||||
"handlers": {
|
|
||||||
"wsgi": {
|
|
||||||
"class": "logging.StreamHandler",
|
|
||||||
"stream": "ext://flask.logging.wsgi_errors_stream",
|
|
||||||
"formatter": "default",
|
|
||||||
},
|
|
||||||
"stdout": {
|
|
||||||
"class": "logging.StreamHandler",
|
|
||||||
"stream": sys.stdout,
|
|
||||||
"formatter": "default",
|
|
||||||
},
|
|
||||||
"file": {
|
|
||||||
"class": "logging.handlers.RotatingFileHandler",
|
|
||||||
"filename": "/app/log/max.log",
|
|
||||||
"formatter": "default",
|
|
||||||
"maxBytes": 1024 * 1024,
|
|
||||||
"backupCount": 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"root": {"level": "INFO", "handlers": ["stdout", "file"]},
|
|
||||||
"gunicorn": {"level": "INFO", "handlers": ["stdout", "file"]},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
logger = logging.getLogger(app.name)
|
|
||||||
logger.setLevel(logging.DEBUG if app.debug else logging.INFO)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
init_logging(app)
|
init_logging(app)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from max.views import redirect
|
|||||||
from .auth import logout
|
from .auth import logout
|
||||||
|
|
||||||
|
|
||||||
DEBUG_DEFAULT_LOGIN = True
|
DEBUG_DEFAULT_LOGIN = False
|
||||||
|
|
||||||
|
|
||||||
class AuthMiddleware(BaseMiddleware):
|
class AuthMiddleware(BaseMiddleware):
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from logging.config import dictConfig
|
||||||
|
|
||||||
|
|
||||||
|
def init_logging(app):
|
||||||
|
handlers = {
|
||||||
|
"stdout": {
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"stream": sys.stdout,
|
||||||
|
"formatter": "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
active_handlers = ["stdout"]
|
||||||
|
if not app.debug:
|
||||||
|
handlers["file"] = {
|
||||||
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
|
"filename": os.path.join(os.environ.get("LOG_DIR", "/app/log"), "max.log"),
|
||||||
|
"formatter": "default",
|
||||||
|
"maxBytes": 1024 * 1024,
|
||||||
|
"backupCount": 5,
|
||||||
|
}
|
||||||
|
active_handlers.append("file")
|
||||||
|
|
||||||
|
dictConfig(
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"formatters": {
|
||||||
|
"default": {"format": "[%(asctime)s] [%(levelname)s]: %(message)s"}
|
||||||
|
},
|
||||||
|
"handlers": handlers,
|
||||||
|
"root": {"level": "INFO", "handlers": active_handlers},
|
||||||
|
"gunicorn": {"level": "INFO", "handlers": active_handlers},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(app.name)
|
||||||
|
logger.setLevel(logging.DEBUG if app.debug else logging.INFO)
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
printf "Black:\n"
|
printf "Black:\n"
|
||||||
black max/
|
black max/
|
||||||
printf "\nIsort:\n"
|
printf "\nIsort:\n"
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PGPASSWORD="$PGSQL_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$PGSQL_HOST" -p "$PGSQL_PORT" -U "$PGSQL_USER" -d "$PGSQL_NAME" \
|
||||||
|
-c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
PGPASSWORD="$PGSQL_PASSWORD" psql -h "$PGSQL_HOST" -p "$PGSQL_PORT" -U "$PGSQL_USER" -d "$PGSQL_NAME"
|
PGPASSWORD="$PGSQL_PASSWORD" psql -h "$PGSQL_HOST" -p "$PGSQL_PORT" -U "$PGSQL_USER" -d "$PGSQL_NAME"
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
source "$(dirname "$0")/db-setup.sh"
|
source ../prod/db-setup.sh
|
||||||
|
|
||||||
flask add-domain finn.st
|
flask add-domain finn.st
|
||||||
flask add-domain stutzenste.in
|
flask add-domain stutzenste.in
|
||||||
flask reset-admin admin@finn.st admin
|
flask reset-admin admin@finn.st admin
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
@@ -15,6 +15,6 @@ wait-for-it --timeout=15 "$PGSQL_HOST:$PGSQL_PORT"
|
|||||||
|
|
||||||
# Create schema in postgresql
|
# Create schema in postgresql
|
||||||
export PGPASSWORD="$PGSQL_PASSWORD"
|
export PGPASSWORD="$PGSQL_PASSWORD"
|
||||||
psql -1 -h "$PGSQL_HOST" -p "$PGSQL_PORT" -U "$PGSQL_USER" -d "$PGSQL_NAME" -f max/db/schema.sql
|
psql -1 -v ON_ERROR_STOP=1 -h "$PGSQL_HOST" -p "$PGSQL_PORT" -U "$PGSQL_USER" -d "$PGSQL_NAME" -f "$(dirname "${BASH_SOURCE[0]}")/schema.sql"
|
||||||
|
|
||||||
echo "end db setup"
|
echo "end db setup"
|
||||||
File renamed without changes.
File renamed without changes.
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
export FLASK_ENV=production
|
|
||||||
gunicorn -w 1 -b 0.0.0.0:8000 max.app:app
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
flask run --host 0.0.0.0 --port 8000
|
|
||||||
File renamed without changes.
Reference in new issue
Block a user