Compare commits

...

8 Commits

Author SHA1 Message Date
forust 81a5b207ac Merge branch 'main' of ssh://gitssh.forust.xyz:2221/forust/homelab
ci / lint-prettier (push) Failing after 8s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:41:31 +02:00
forust e3d5970ae3 chore: remove untracked README.md
ci / lint-prettier (push) Failing after 11s
ci / lint-ruff (push) Successful in 5s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-10 11:39:20 +02:00
forust 68630eb773 fix(edu): read diary event times directly from DOM, drop 25 AJAX clicks
ci / lint-prettier (push) Successful in 9s
ci / lint-ruff (push) Successful in 6s
ci / lint-yaml (push) Successful in 10s
ci / lint-dockerfiles (push) Successful in 7s
ci / validate (push) Successful in 6s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
_collect_event_times re-clicked every a.event-link and waited ~3s per
event for a visible span.data, but the calendar embeds all times in
div.event-full-info[data-event-full-info-id] span.data already. The old
loop took ~109s for 25 events and collected 0 (original divs stay
sf-hidden), effectively hanging /diary. Now a single evaluate reads all
times (~3.7s), parsing HH:MM from p.date span.data.
2026-09-10 00:31:04 +02:00
forust dad9cf2104 feat(edu): parse event times in /diary and drop weekend days
ci / lint-prettier (push) Successful in 9s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 6s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
- fetch each event's time via Playwright (click event-link, read span.data, close fancybox) and render as 'title (HH:MM)'
- '08:00' placeholder renders as localized 'unknown' (time_unknown key in ru/uk/en)
- diary week view shows Mon-Fri only (title ends at Friday)
- diary month view skips Sat/Sun by weekday_idx with name-based fallback
- schedule keyboard drops Sat/Sun day buttons
2026-09-10 00:05:56 +02:00
forust 60886e8be2 style(edu): ruff-format webinar-checker/checker.py
ci / lint-prettier (push) Successful in 13s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 6s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
2026-09-09 23:47:04 +02:00
forust 4528321225 fix(edu): add TZ to .env.example 2026-09-09 11:46:35 +02:00
forust b246a3dea1 fix(edu): review findings for checker.py i18n — group chat language via resolve_lang/chat: keys (default uk), weekday normalization with _norm_day + logging, drop dead translation keys, html.escape, single lang lookup, distinct whitelist emoji 2026-09-09 11:44:17 +02:00
forust 4c59a2d2fe lang(edu): translate k8s manifest comments to English only
- restore-seed-job.yaml.example: translate runbook to English
- secrets.yaml.example: translate section headers to English
- webinar-checker.yaml: translate initContainer dependency-order comments to English

Co-authored-by: assistant
2026-09-09 10:46:36 +02:00
7 changed files with 587 additions and 150 deletions
+1
View File
@@ -9,5 +9,6 @@ WEBINAR_CHECK_INTERVAL=60
REDIS_HOST=redis
REDIS_PORT=6379
PLAYWRIGHT_WS=ws://playwright-service:3000/ws
TZ=Europe/Kyiv
WEBINAR_TELEGRAM_TOKEN=your_telegram_bot_token_here
WEBINAR_ADMIN_ID=123456789
View File
+6 -6
View File
@@ -1,17 +1,17 @@
# Разовый Job для переноса состояния redis из docker compose в k8s (maintenance window).
# Файл .example -> deploy-пайплайн его не применяет (маска *.example.yaml).
# One-time Job to migrate redis state from docker compose to k8s (maintenance window).
# The .example file is not applied by the deploy pipeline (mask *.example.yaml).
#
# Runbook:
# 1. docker compose -f <repo>/edu_master/compose.yaml stop # SIGTERM -> redis сбросит dump.rdb
# 1. docker compose -f <repo>/edu_master/compose.yaml stop # SIGTERM -> redis will flush dump.rdb
# 2. docker run --rm -v edu_master_redis-data:/data \
# -v /tmp/edu-master-backup:/backup \
# redis:alpine sh -c "cp /data/dump.rdb /backup/ && ls -la /backup"
# 3. kubectl apply -f edu_master/k8s/namespace.yaml
# 4. kubectl apply -f <только PVC из redis.yaml> # seed строго ДО старта redis-пода
# 4. kubectl apply -f <only the PVC from redis.yaml> # seed must come BEFORE redis pod starts
# 5. kubectl apply -f edu_master/k8s/restore-seed-job.yaml.example
# kubectl wait --for=condition=complete job/redis-restore-seed -n edu-master --timeout=120s
# 6. kubectl delete job redis-restore-seed -n edu-master
# 7. kubectl apply -f edu_master/k8s/ -R # остальные манифесты
# 7. kubectl apply -f edu_master/k8s/ -R # apply remaining manifests
apiVersion: batch/v1
kind: Job
metadata:
@@ -47,4 +47,4 @@ spec:
- name: backup
hostPath:
path: /tmp/edu-master-backup
type: DirectoryOrCreate
type: DirectoryOrCreate
+3 -2
View File
@@ -5,7 +5,7 @@ metadata:
namespace: edu-master
type: Opaque
stringData:
# PHPSESSID keeper
# Session keeper credentials
KEEPER_LOGIN: ""
KEEPER_PASSWORD: ""
KEEPER_INTERVAL: "10"
@@ -23,4 +23,5 @@ stringData:
WEBINAR_CHECK_INTERVAL: "60"
# Database
REDIS_HOST: "redis"
REDIS_PORT: "6379"
REDIS_PORT: "6379"
TZ: "Europe/Kyiv"
+5 -2
View File
@@ -15,9 +15,9 @@ spec:
labels:
app: edu-master-webinar-checker
spec:
# Enforces dependency order like compose depends_on:
# redis healthy -> session-keeper healthy (EXISTS EDU_PHPSESSID) -> playwright started
initContainers:
# Держит порядок зависимостей как в compose depends_on:
# redis healthy -> session-keeper healthy (EXISTS EDU_PHPSESSID) -> playwright started
- name: wait-deps
image: redis:alpine
command:
@@ -50,6 +50,9 @@ spec:
envFrom:
- secretRef:
name: edu-master-secrets
env:
- name: TZ
value: "Europe/Kyiv"
resources:
requests:
cpu: 25m
File diff suppressed because it is too large Load Diff
+95
View File
@@ -0,0 +1,95 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: esp32
labels:
app.kubernetes.io/name: esp32
---
apiVersion: v1
kind: Service
metadata:
name: esp
namespace: esp32
labels:
app.kubernetes.io/name: esp32
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: v1
kind: Endpoints
metadata:
name: esp
namespace: esp32
labels:
app.kubernetes.io/name: esp32
subsets:
- addresses:
- ip: 192.168.88.88
ports:
- name: http
port: 80
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: strip-esp-headers
namespace: esp32
labels:
app.kubernetes.io/name: esp32
spec:
headers:
customRequestHeaders:
Cookie: ""
Referer: ""
Origin: ""
User-Agent: ""
Accept: ""
Accept-Encoding: ""
Accept-Language: ""
Upgrade-Insecure-Requests: ""
Cache-Control: ""
Pragma: ""
Connection: ""
Te: ""
Sec-Fetch-Dest: ""
Sec-Fetch-Mode: ""
Sec-Fetch-Site: ""
Sec-Fetch-User: ""
Sec-CH-UA: ""
Sec-CH-UA-Mobile: ""
Sec-CH-UA-Platform: ""
X-Forwarded-For: ""
X-Forwarded-Host: ""
X-Forwarded-Port: ""
X-Forwarded-Proto: ""
X-Forwarded-Server: ""
Forwarded: ""
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: esp
namespace: esp32
labels:
app.kubernetes.io/name: esp32
spec:
entryPoints:
- websecure
routes:
- match: Host(`esp.forust.xyz`)
kind: Rule
middlewares:
- name: strip-esp-headers
namespace: esp32
services:
- kind: Service
name: esp
namespace: esp32
port: 80
tls:
certResolver: letsencrypt