after migration
13
.gitignore
vendored
|
|
@ -111,3 +111,16 @@ dmypy.json
|
|||
*.sqlite3
|
||||
.github
|
||||
.venv
|
||||
|
||||
# Virtual environment
|
||||
venv/
|
||||
.autoenv.zsh
|
||||
.autoenv_leave.zsh
|
||||
.autoenv.*.zsh
|
||||
|
||||
# Python cache
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
|
|
|
|||
15
README.md
|
|
@ -22,10 +22,11 @@
|
|||
- **📚 BookStack Wiki**: Documentation and knowledge base (port 6875)
|
||||
- **🤖 Ollama + Open WebUI**: Local LLM chatbot interface (port 8080)
|
||||
- **📨 Matrix Synapse**: Print order collection and payment tracking (port 8008)
|
||||
- **🐳 Portainer**: Container management dashboard (port 9000)
|
||||
- **<EFBFBD> JupyterHub**: Multi-user Jupyter notebook server for drone programming (port 8001)
|
||||
- **<EFBFBD> Element Web**: Browser-based Matrix chat client (port 8082)
|
||||
- **<EFBFBD>🐳 Portainer**: Container management dashboard (port 9000)
|
||||
- **📓 JupyterHub**: Multi-user Jupyter notebook server for drone programming (port 8001)
|
||||
- **🦊 Forgejo**: Self-hosted Git service for code collaboration (port 3003)
|
||||
- **<EFBFBD>🔄 Watchtower**: Automatic container updates every 24 hours
|
||||
- **🔄 Watchtower**: Automatic container updates every 24 hours
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -126,9 +127,13 @@ graph TB
|
|||
|
||||
### Prerequisites
|
||||
|
||||
**On the host system:**
|
||||
- **Docker** & **Docker Compose** installed
|
||||
- **curl** - for testing and healthchecks (install: `brew install curl` on macOS)
|
||||
- **Poppler** (for pdf2image - included in Docker)
|
||||
- **Port availability**: 80, 3003, 6875, 8001, 8008, 8080, 9000, 11434
|
||||
- **Port availability**: 80, 3003, 6875, 8001, 8008, 8080, 8082, 9000, 11434
|
||||
|
||||
**Note:** Python dependencies are containerized and don't need to be installed on the host.
|
||||
|
||||
### Installation
|
||||
|
||||
|
|
@ -158,8 +163,10 @@ graph TB
|
|||
- Open WebUI: <http://localhost:8080>
|
||||
- Portainer: <http://localhost:9000>
|
||||
- Matrix: <http://localhost:8008>
|
||||
- Element Web: <http://localhost:8082>
|
||||
- JupyterHub: <http://localhost:8001>
|
||||
- Forgejo: <http://localhost:3003>
|
||||
- Forgejo: <http://localhost:3003>
|
||||
|
||||
### First-Time Setup
|
||||
|
||||
|
|
|
|||
40
create_room.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Create a Matrix room for print orders
|
||||
"""
|
||||
import json
|
||||
import requests
|
||||
|
||||
access_token = "syt_ZWluc3p3b3ZpZXI_vebsCCpDYUkfsqLgnvjz_1WOI0g"
|
||||
user_id = "@einszwovier:124.local"
|
||||
|
||||
# Create room
|
||||
data = {
|
||||
"name": "Print Orders",
|
||||
"topic": "PDF print order submissions from the web app",
|
||||
"preset": "private_chat",
|
||||
"visibility": "private"
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
"http://localhost:8008/_matrix/client/r0/createRoom",
|
||||
json=data,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print(f"Room creation response: {response.status_code}")
|
||||
print(json.dumps(response.json(), indent=2))
|
||||
|
||||
if response.status_code == 200:
|
||||
room_id = response.json()['room_id']
|
||||
print(f"\n✅ Room created successfully!")
|
||||
print(f"Room ID: {room_id}")
|
||||
print(f"\n📋 Add this to your .env file:")
|
||||
print(f"MATRIX_ROOM={room_id}")
|
||||
else:
|
||||
print(f"\n❌ Room creation failed")
|
||||
|
|
@ -65,12 +65,7 @@ services:
|
|||
mem_limit: 16g
|
||||
cpus: 6.0
|
||||
mem_reservation: 4g
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:11434/ || exit 1"]
|
||||
interval: 60s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
# Healthcheck removed - ollama image doesn't include curl
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "description=Local LLM inference engine"
|
||||
|
|
@ -179,11 +174,7 @@ services:
|
|||
- WATCHTOWER_INCLUDE_RESTARTING=true
|
||||
- WATCHTOWER_LABEL_ENABLE=true
|
||||
command: --cleanup --interval 86400 --label-enable
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pgrep watchtower || exit 1"]
|
||||
interval: 60s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
# Healthcheck removed - watchtower runs as background process, pgrep check unreliable
|
||||
labels:
|
||||
- "description=Watchtower Auto-Update Service"
|
||||
- "maintainer=studio einszwovier"
|
||||
|
|
@ -198,16 +189,7 @@ services:
|
|||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- portainer_data:/data
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"curl -f http://localhost:9000/api/system/status || exit 1",
|
||||
]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
# Healthcheck removed - portainer image doesn't include curl
|
||||
labels:
|
||||
- "description=Portainer Container Management UI"
|
||||
- "maintainer=studio einszwovier"
|
||||
|
|
@ -232,16 +214,7 @@ services:
|
|||
cpus: 1.0
|
||||
depends_on:
|
||||
- web
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"curl -f http://localhost:8001/hub/health || curl -f http://localhost:8001/hub/ || exit 1",
|
||||
]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
# Healthcheck removed - jupyterhub custom image doesn't include curl
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "description=JupyterHub for interactive notebooks"
|
||||
|
|
@ -286,12 +259,7 @@ services:
|
|||
mem_limit: 512m
|
||||
cpus: 0.5
|
||||
mem_reservation: 128m
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 20s
|
||||
# Healthcheck removed - element-web image doesn't include curl
|
||||
depends_on:
|
||||
synapse:
|
||||
condition: service_started
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ Element Web is a browser-based Matrix client that connects to the studio einszwo
|
|||
|
||||
## Configuration
|
||||
|
||||
The `config.json` file configures Element Web to connect to the local Synapse homeserver at `http://einszwovier.local:8008`.
|
||||
The `config.json` file configures Element Web to connect to the local Synapse homeserver at `http://124.local:8008`.
|
||||
|
||||
### Key Settings
|
||||
|
||||
- **Homeserver**: Points to local Synapse instance
|
||||
- **Server name**: `einszwovier.local`
|
||||
- **Server name**: `124.local`
|
||||
- **Brand**: "studio einszwovier Chat"
|
||||
- **Default language**: German (DE)
|
||||
- **Default theme**: Light mode
|
||||
|
|
@ -17,13 +17,13 @@ The `config.json` file configures Element Web to connect to the local Synapse ho
|
|||
|
||||
## Access
|
||||
|
||||
- **URL**: `http://einszwovier.local:8082`
|
||||
- **URL**: `http://124.local:8082`
|
||||
- **No app required**: Works in any modern web browser
|
||||
- **Mobile friendly**: Responsive design works on phones and tablets
|
||||
|
||||
## Usage
|
||||
|
||||
1. Navigate to `http://einszwovier.local:8082`
|
||||
1. Navigate to `http://124.local:8082`
|
||||
2. Click "Sign In" or "Create Account"
|
||||
3. Use existing Matrix credentials or create a new account
|
||||
4. Join rooms (e.g., the print order room)
|
||||
|
|
@ -49,7 +49,7 @@ Element Web is managed by Watchtower and updates automatically with the rest of
|
|||
|
||||
- Ensure Synapse is running: `docker-compose ps synapse`
|
||||
- Check Synapse logs: `docker-compose logs synapse`
|
||||
- Verify hostname resolution: `ping einszwovier.local`
|
||||
- Verify hostname resolution: `ping 124.local`
|
||||
|
||||
**Login fails:**
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "http://einszwovier.local:8008",
|
||||
"server_name": "einszwovier.local"
|
||||
"base_url": "http://124.local:8008",
|
||||
"server_name": "124.local"
|
||||
}
|
||||
},
|
||||
"brand": "studio einszwovier Chat",
|
||||
|
|
@ -16,11 +16,11 @@
|
|||
},
|
||||
"room_directory": {
|
||||
"servers": [
|
||||
"einszwovier.local"
|
||||
"124.local"
|
||||
]
|
||||
},
|
||||
"enable_presence_by_hs_url": {
|
||||
"http://einszwovier.local:8008": true
|
||||
"http://124.local:8008": true
|
||||
},
|
||||
"terms_and_conditions_links": [],
|
||||
"privacy_policy_url": null
|
||||
|
|
|
|||
0
forgejo/data/git/.ssh/authorized_keys
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
forgejo/data/gitea/avatars/aab74637b6c33c04d73a89d1f584f407
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -1,5 +1,8 @@
|
|||
APP_NAME = Forgejo: Beyond coding. We forge.
|
||||
APP_NAME = einszwovier forge
|
||||
RUN_MODE = prod
|
||||
APP_SLOGAN =
|
||||
RUN_USER = git
|
||||
WORK_PATH = /data/gitea
|
||||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
|
|
@ -13,14 +16,16 @@ TEMP_PATH = /data/gitea/uploads
|
|||
|
||||
[server]
|
||||
APP_DATA_PATH = /data/gitea
|
||||
DOMAIN = localhost
|
||||
SSH_DOMAIN = localhost
|
||||
DOMAIN = 124.local
|
||||
SSH_DOMAIN = 124.local
|
||||
HTTP_PORT = 3000
|
||||
ROOT_URL =
|
||||
ROOT_URL = http://124.local:3003/
|
||||
DISABLE_SSH = false
|
||||
SSH_PORT = 22
|
||||
SSH_LISTEN_PORT = 22
|
||||
LFS_START_SERVER = false
|
||||
LFS_START_SERVER = true
|
||||
LFS_JWT_SECRET = hZvHy32wQr50I0x51W9WqQvYqNEfm45PqAoq7KJcw2k
|
||||
OFFLINE_MODE = true
|
||||
|
||||
[database]
|
||||
PATH = /data/gitea/gitea.db
|
||||
|
|
@ -30,12 +35,15 @@ NAME = gitea
|
|||
USER = root
|
||||
PASSWD =
|
||||
LOG_SQL = false
|
||||
SCHEMA =
|
||||
SSL_MODE = disable
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||
|
||||
[session]
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
||||
PROVIDER = file
|
||||
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /data/gitea/avatars
|
||||
|
|
@ -50,14 +58,43 @@ LEVEL = info
|
|||
ROOT_PATH = /data/gitea/log
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = false
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY =
|
||||
REVERSE_PROXY_LIMIT = 1
|
||||
REVERSE_PROXY_TRUSTED_PROXIES = *
|
||||
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3NjI3NzI1NDN9.XRM_LxqMxCNJC4odRqZcNZ-C8LNxCV1pDFGi5ks789s
|
||||
PASSWORD_HASH_ALGO = pbkdf2_hi
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = true
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
NO_REPLY_ADDRESS = noreply.localhost
|
||||
|
||||
[lfs]
|
||||
PATH = /data/git/lfs
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = true
|
||||
ENABLE_OPENID_SIGNUP = true
|
||||
|
||||
[cron.update_checker]
|
||||
ENABLED = true
|
||||
|
||||
[repository.pull-request]
|
||||
DEFAULT_MERGE_STYLE = merge
|
||||
|
||||
[repository.signing]
|
||||
DEFAULT_TRUST_MODEL = committer
|
||||
|
||||
[oauth2]
|
||||
JWT_SECRET = DCWJLYmNbdJngkBLfZBNHX9IHBFE1A-Op3EvURtCsU0
|
||||
|
|
|
|||
22
forgejo/data/gitea/home/.gitconfig
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[diff]
|
||||
algorithm = histogram
|
||||
[core]
|
||||
logallrefupdates = true
|
||||
quotePath = false
|
||||
commitGraph = true
|
||||
[gc]
|
||||
reflogexpire = 90
|
||||
writeCommitGraph = true
|
||||
[user]
|
||||
name = Gitea
|
||||
email = gitea@fake.local
|
||||
[receive]
|
||||
advertisePushOptions = true
|
||||
procReceiveRefs = refs/for
|
||||
[fetch]
|
||||
writeCommitGraph = true
|
||||
[safe]
|
||||
directory = *
|
||||
[uploadpack]
|
||||
allowfilter = true
|
||||
allowAnySHA1InWant = true
|
||||
1
forgejo/data/gitea/indexers/issues.bleve/index_meta.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"storage":"boltdb","index_type":"scorch"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":4}
|
||||
BIN
forgejo/data/gitea/indexers/issues.bleve/store/root.bolt
Normal file
BIN
forgejo/data/gitea/queues/common/000002.ldb
Normal file
1
forgejo/data/gitea/queues/common/CURRENT
Normal file
|
|
@ -0,0 +1 @@
|
|||
MANIFEST-000004
|
||||
0
forgejo/data/gitea/queues/common/LOCK
Normal file
16
forgejo/data/gitea/queues/common/LOG
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
=============== Nov 10, 2025 (CET) ===============
|
||||
12:02:27.139922 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||
12:02:27.141510 db@open opening
|
||||
12:02:27.141943 version@stat F·[] S·0B[] Sc·[]
|
||||
12:02:27.142289 db@janitor F·2 G·0
|
||||
12:02:27.142333 db@open done T·789.083µs
|
||||
=============== Nov 10, 2025 (CET) ===============
|
||||
14:41:11.536178 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||
14:41:11.537691 version@stat F·[] S·0B[] Sc·[]
|
||||
14:41:11.537733 db@open opening
|
||||
14:41:11.537879 journal@recovery F·1
|
||||
14:41:11.537972 journal@recovery recovering @1
|
||||
14:41:11.538886 memdb@flush created L0@2 N·26 S·542B "act..igh,v26":"web..low,v17"
|
||||
14:41:11.539093 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||
14:41:11.543912 db@janitor F·3 G·0
|
||||
14:41:11.543982 db@open done T·6.225416ms
|
||||
BIN
forgejo/data/gitea/queues/common/MANIFEST-000004
Normal file
BIN
forgejo/data/gitea/sessions/6/7/671ec6cf26e818fa
Normal file
|
|
@ -11,7 +11,7 @@ async def send_order(pdf_path: str, analysis: dict, room_id: str, name: str, com
|
|||
"""
|
||||
matrix_user = os.environ.get("MATRIX_USER")
|
||||
matrix_pass = os.environ.get("MATRIX_PASS")
|
||||
homeserver = os.environ.get("MATRIX_HOMESERVER", "http://einszwovier.local:8008")
|
||||
homeserver = os.environ.get("MATRIX_HOMESERVER", "http://124.local:8008")
|
||||
|
||||
if not matrix_user or not matrix_pass:
|
||||
raise RuntimeError("Missing MATRIX_USER or MATRIX_PASS in environment")
|
||||
|
|
|
|||
4
main.py
|
|
@ -14,7 +14,7 @@ from dotenv import load_dotenv
|
|||
load_dotenv()
|
||||
|
||||
# Get server hostname from environment
|
||||
SERVER_HOSTNAME = os.environ.get("SERVER_HOSTNAME", "einszwovier.local")
|
||||
SERVER_HOSTNAME = os.environ.get("SERVER_HOSTNAME", "124.local")
|
||||
BOOKSTACK_PORT = os.environ.get("BOOKSTACK_PORT", "6875")
|
||||
OPENWEBUI_PORT = os.environ.get("OPENWEBUI_PORT", "8080")
|
||||
PORTAINER_PORT = os.environ.get("PORTAINER_PORT", "9000")
|
||||
|
|
@ -162,7 +162,7 @@ def send_order_endpoint(
|
|||
analysis = analyze_pdf(path)
|
||||
|
||||
# Get Matrix room ID from environment
|
||||
matrix_room = os.environ.get("MATRIX_ROOM", "!eFWbWEnYsgeIKqyfjw:einszwovier.local")
|
||||
matrix_room = os.environ.get("MATRIX_ROOM", "!PuLwSlWKNgNKvhhCIr:124.local")
|
||||
|
||||
try:
|
||||
send_order_sync(
|
||||
|
|
|
|||
30
matrix/data.backup.einszwovier/homeserver.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Configuration file for Synapse.
|
||||
|
||||
server_name: "einszwovier.local"
|
||||
pid_file: /data/homeserver.pid
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
type: http
|
||||
x_forwarded: true
|
||||
resources:
|
||||
- names: [client, federation]
|
||||
compress: false
|
||||
database:
|
||||
name: sqlite3
|
||||
args:
|
||||
database: /data/homeserver.db
|
||||
|
||||
# Connection and performance settings
|
||||
max_upload_size: 50M
|
||||
url_preview_enabled: false
|
||||
|
||||
log_config: "/data/localhost.log.config"
|
||||
media_store_path: /data/media_store
|
||||
registration_shared_secret: "D2mw3LqNKe98ga-pYO1l5KbXf^jgx&s5yjq&ipAGjln:AzLag8"
|
||||
report_stats: false
|
||||
macaroon_secret_key: "T26aaiHWLHbm+P6fi_8:VXTIn0W_kHH__CQAdhPyaLhBe~OG*_"
|
||||
form_secret: "k,C38Dw^6b8Y+9-cSQpLb@GPoS*1POr8GDWXsLMKLHEU2+&q-@"
|
||||
signing_key_path: "/data/localhost.signing.key"
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
39
matrix/data.backup.einszwovier/localhost.log.config
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
version: 1
|
||||
|
||||
formatters:
|
||||
precise:
|
||||
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
|
||||
|
||||
handlers:
|
||||
|
||||
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
|
||||
loggers:
|
||||
# This is just here so we can leave `loggers` in the config regardless of whether
|
||||
# we configure other loggers below (avoid empty yaml dict error).
|
||||
_placeholder:
|
||||
level: "INFO"
|
||||
|
||||
|
||||
|
||||
synapse.storage.SQL:
|
||||
# beware: increasing this to DEBUG will make synapse log sensitive
|
||||
# information such as access tokens.
|
||||
level: INFO
|
||||
|
||||
|
||||
|
||||
|
||||
root:
|
||||
level: INFO
|
||||
|
||||
|
||||
handlers: [console]
|
||||
|
||||
|
||||
disable_existing_loggers: false
|
||||
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
|
@ -1,6 +1,6 @@
|
|||
# Configuration file for Synapse.
|
||||
|
||||
server_name: "einszwovier.local"
|
||||
server_name: "124.local"
|
||||
pid_file: /data/homeserver.pid
|
||||
listeners:
|
||||
- port: 8008
|
||||
|
|
@ -28,3 +28,10 @@ form_secret: "k,C38Dw^6b8Y+9-cSQpLb@GPoS*1POr8GDWXsLMKLHEU2+&q-@"
|
|||
signing_key_path: "/data/localhost.signing.key"
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
|
||||
# Allow guest access
|
||||
allow_guest_access: true
|
||||
|
||||
# Enable registration
|
||||
enable_registration: true
|
||||
enable_registration_without_verification: true
|
||||
|
|
|
|||
60
register_user.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Register a user on Matrix server using shared secret
|
||||
"""
|
||||
import hmac
|
||||
import hashlib
|
||||
import json
|
||||
import requests
|
||||
|
||||
# Get nonce
|
||||
nonce_response = requests.get("http://localhost:8008/_synapse/admin/v1/register")
|
||||
nonce = nonce_response.json()["nonce"]
|
||||
|
||||
print(f"Got nonce: {nonce[:20]}...")
|
||||
|
||||
# Registration details
|
||||
username = "einszwovier"
|
||||
password = "einszwo4"
|
||||
admin = False
|
||||
shared_secret = "D2mw3LqNKe98ga-pYO1l5KbXf^jgx&s5yjq&ipAGjln:AzLag8"
|
||||
|
||||
# Generate MAC
|
||||
mac = hmac.new(
|
||||
key=shared_secret.encode('utf8'),
|
||||
digestmod=hashlib.sha1,
|
||||
)
|
||||
|
||||
mac.update(nonce.encode('utf8'))
|
||||
mac.update(b"\x00")
|
||||
mac.update(username.encode('utf8'))
|
||||
mac.update(b"\x00")
|
||||
mac.update(password.encode('utf8'))
|
||||
mac.update(b"\x00")
|
||||
mac.update(b"notadmin" if not admin else b"admin")
|
||||
|
||||
mac_str = mac.hexdigest()
|
||||
|
||||
# Register user
|
||||
data = {
|
||||
"nonce": nonce,
|
||||
"username": username,
|
||||
"password": password,
|
||||
"admin": admin,
|
||||
"mac": mac_str
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
"http://localhost:8008/_synapse/admin/v1/register",
|
||||
json=data
|
||||
)
|
||||
|
||||
print(f"\nRegistration response: {response.status_code}")
|
||||
print(json.dumps(response.json(), indent=2))
|
||||
|
||||
if response.status_code == 200:
|
||||
print(f"\n✅ User registered successfully!")
|
||||
print(f"User ID: {response.json()['user_id']}")
|
||||
print(f"Access Token: {response.json()['access_token']}")
|
||||
else:
|
||||
print(f"\n❌ Registration failed")
|
||||
62
setup_matrix.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Setup script for Matrix: register user and create room
|
||||
"""
|
||||
import asyncio
|
||||
import os
|
||||
from nio import AsyncClient, RegisterResponse, RoomCreateResponse
|
||||
|
||||
async def setup_matrix():
|
||||
homeserver = "http://124.local:8008"
|
||||
username = "einszwovier"
|
||||
password = "einszwo4"
|
||||
|
||||
client = AsyncClient(homeserver)
|
||||
|
||||
print("🔧 Setting up Matrix server...")
|
||||
print(f" Homeserver: {homeserver}")
|
||||
print(f" Username: {username}")
|
||||
|
||||
# Register the user
|
||||
print("\n📝 Registering user...")
|
||||
response = await client.register(
|
||||
username=username,
|
||||
password=password
|
||||
)
|
||||
|
||||
if isinstance(response, RegisterResponse):
|
||||
print(f" ✅ User registered: {response.user_id}")
|
||||
user_id = response.user_id
|
||||
else:
|
||||
print(f" ℹ️ User might already exist, trying to login...")
|
||||
# Try to login instead
|
||||
response = await client.login(password)
|
||||
if response.user_id:
|
||||
print(f" ✅ Logged in as: {response.user_id}")
|
||||
user_id = response.user_id
|
||||
else:
|
||||
print(f" ❌ Failed: {response}")
|
||||
await client.close()
|
||||
return
|
||||
|
||||
# Create a room
|
||||
print("\n🏠 Creating print orders room...")
|
||||
response = await client.room_create(
|
||||
name="Print Orders",
|
||||
topic="PDF print order submissions from the web app",
|
||||
is_public=False
|
||||
)
|
||||
|
||||
if isinstance(response, RoomCreateResponse):
|
||||
print(f" ✅ Room created!")
|
||||
print(f" Room ID: {response.room_id}")
|
||||
print(f"\n✅ Setup complete!")
|
||||
print(f"\n📋 Add this to your .env file:")
|
||||
print(f"MATRIX_ROOM={response.room_id}")
|
||||
else:
|
||||
print(f" ❌ Failed to create room: {response}")
|
||||
|
||||
await client.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(setup_matrix())
|
||||
|
|
@ -538,6 +538,98 @@ a.link-card:hover,
|
|||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
ARCHITECTURE SPOILER
|
||||
======================================== */
|
||||
|
||||
.architecture-spoiler {
|
||||
margin: 0 auto 1.5rem;
|
||||
max-width: 1200px;
|
||||
width: calc(100% - 2rem);
|
||||
background: #ffffff;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.architecture-summary {
|
||||
padding: 0.8rem 1.2rem;
|
||||
background: #f8f9fa;
|
||||
color: #2C3E50;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
transition: background-color 0.2s ease;
|
||||
user-select: none;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.architecture-summary:hover {
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
.architecture-summary i {
|
||||
font-size: 1.1rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.architecture-spoiler[open] .architecture-summary {
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
.architecture-content {
|
||||
padding: 1.5rem;
|
||||
background: #ffffff;
|
||||
text-align: center;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.architecture-image {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
max-height: 60vh;
|
||||
object-fit: contain;
|
||||
border-radius: 4px;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.architecture-image:hover {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.architecture-caption {
|
||||
margin-top: 1rem;
|
||||
color: #6c757d;
|
||||
font-size: 0.9rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Responsive adjustments for mobile */
|
||||
@media (max-width: 768px) {
|
||||
.architecture-spoiler {
|
||||
width: calc(100% - 1rem);
|
||||
}
|
||||
|
||||
.architecture-content {
|
||||
padding: 1rem;
|
||||
max-height: 50vh;
|
||||
}
|
||||
|
||||
.architecture-image {
|
||||
max-height: 45vh;
|
||||
}
|
||||
|
||||
.architecture-summary {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.7rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ========================================
|
||||
BUTTONS
|
||||
|
|
|
|||
BIN
static/images/architecture.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
|
|
@ -36,8 +36,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Information and Tools Cards -->
|
||||
<div class="link-cards-grid">
|
||||
<a class="link-card" href="/about">
|
||||
|
|
@ -76,7 +74,7 @@
|
|||
</div>
|
||||
</a>
|
||||
|
||||
<a class="link-card" href="http://{{ server_hostname }}:8001" target="_blank">
|
||||
<a class="link-card" href="http://{{ server_hostname }}:8001/hub/" target="_blank">
|
||||
<i class="fas fa-code card-icon"></i>
|
||||
<div class="card-content">
|
||||
<div class="title">JupyterHub</div>
|
||||
|
|
@ -117,6 +115,20 @@
|
|||
|
||||
<!-- Footer with Admin Panel and Source Link -->
|
||||
<footer class="footer">
|
||||
<!-- Architecture Diagram Spoiler -->
|
||||
<details class="architecture-spoiler">
|
||||
<summary class="architecture-summary">
|
||||
<i class="fas fa-sitemap"></i>
|
||||
<span>Systemarchitektur anzeigen</span>
|
||||
</summary>
|
||||
<div class="architecture-content">
|
||||
<img src="/static/images/architecture.png" alt="Studio einszwovier Architecture Diagram"
|
||||
class="architecture-image">
|
||||
<p class="architecture-caption">Übersicht über alle Dienste und deren Zusammenspiel im Studio einszwovier
|
||||
System</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<div class="footer-container">
|
||||
<a href="http://{{ server_hostname }}:{{ portainer_port }}" target="_blank" class="admin-link">Admin Panel
|
||||
(Portainer)</a>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ async def test_connection(homeserver_url: str):
|
|||
"""Test connection to Matrix homeserver"""
|
||||
print(f"\n🔍 Testing connection to: {homeserver_url}")
|
||||
|
||||
matrix_user = os.environ.get("MATRIX_USER", "@einszwovier:einszwovier.local")
|
||||
matrix_user = os.environ.get("MATRIX_USER", "@einszwovier:124.local")
|
||||
matrix_pass = os.environ.get("MATRIX_PASS", "einszwo4")
|
||||
|
||||
client = AsyncClient(homeserver_url, matrix_user)
|
||||
|
|
@ -44,7 +44,7 @@ async def main():
|
|||
test_urls = [
|
||||
"http://localhost:8008",
|
||||
"http://127.0.0.1:8008",
|
||||
"http://einszwovier.local:8008",
|
||||
"http://124.local:8008",
|
||||
]
|
||||
|
||||
for url in test_urls:
|
||||
|
|
@ -52,7 +52,7 @@ async def main():
|
|||
|
||||
print("\n" + "=" * 60)
|
||||
print("Recommendation:")
|
||||
print("If localhost/127.0.0.1 works but einszwovier.local fails,")
|
||||
print("If localhost/127.0.0.1 works but 124.local fails,")
|
||||
print("configure Element to use: http://localhost:8008")
|
||||
print("=" * 60)
|
||||
|
||||
|
|
|
|||