fix: release v0.2.1 lesson deletes and large uploads
- Raise Traefik read timeout to 1h (compose dev/prod + k3s HelmChartConfig) so admin video uploads up to 200MB no longer 502 mid-upload. - Migration 0029: cascade watch/quiz history on lesson delete and unlink dependent lessons, so removing a lesson or chapter stops 500ing. - Add the Apollo cluster Helm overlay (values-apollo.yaml) for the deployed environment. - k3s Traefik chart config also enables access logs, cross-namespace IngressRoutes, and fixes the Prometheus scrape port. Bump appVersion/product.go/values tags to 0.2.1; chart version 0.2.3.
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/Panahifarah/pargar/releases/tag/v0.2.0"><img src="https://img.shields.io/github/v/tag/Panahifarah/pargar?label=release&color=5B4CDB" alt="release" /></a>
|
<a href="https://github.com/Panahifarah/pargar/releases/tag/v0.2.1"><img src="https://img.shields.io/github/v/tag/Panahifarah/pargar?label=release&color=5B4CDB" alt="release" /></a>
|
||||||
<a href="LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-5B4CDB" alt="AGPL-3.0" /></a>
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-5B4CDB" alt="AGPL-3.0" /></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ func (s *Server) handleMeta(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func appBuild() (version, built string) {
|
func appBuild() (version, built string) {
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
built = "dev"
|
built = "dev"
|
||||||
info, ok := debug.ReadBuildInfo()
|
info, ok := debug.ReadBuildInfo()
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -594,7 +594,7 @@ func appBuild() (version, built string) {
|
|||||||
built = setting.Value[:10]
|
built = setting.Value[:10]
|
||||||
}
|
}
|
||||||
if setting.Key == "vcs.revision" && len(setting.Value) >= 7 {
|
if setting.Key == "vcs.revision" && len(setting.Value) >= 7 {
|
||||||
version = "0.2.0+" + setting.Value[:7]
|
version = "0.2.1+" + setting.Value[:7]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return version, built
|
return version, built
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
-- 0029_lesson_delete_cascades.sql
|
||||||
|
-- Make deleting a lesson (directly, or via its chapter) work cleanly.
|
||||||
|
--
|
||||||
|
-- Previously only mcq_questions cascaded; watch/quiz history blocked the delete
|
||||||
|
-- with a 500. Progress/history rows now go away with the lesson, while lessons
|
||||||
|
-- that merely *required* the deleted one are unlinked (never deleted).
|
||||||
|
|
||||||
|
ALTER TABLE watch_sessions DROP CONSTRAINT IF EXISTS watch_sessions_lesson_id_fkey;
|
||||||
|
ALTER TABLE watch_sessions ADD CONSTRAINT watch_sessions_lesson_id_fkey
|
||||||
|
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE watch_heartbeats DROP CONSTRAINT IF EXISTS watch_heartbeats_lesson_id_fkey;
|
||||||
|
ALTER TABLE watch_heartbeats ADD CONSTRAINT watch_heartbeats_lesson_id_fkey
|
||||||
|
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE lesson_progress DROP CONSTRAINT IF EXISTS lesson_progress_lesson_id_fkey;
|
||||||
|
ALTER TABLE lesson_progress ADD CONSTRAINT lesson_progress_lesson_id_fkey
|
||||||
|
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE quiz_attempts DROP CONSTRAINT IF EXISTS quiz_attempts_lesson_id_fkey;
|
||||||
|
ALTER TABLE quiz_attempts ADD CONSTRAINT quiz_attempts_lesson_id_fkey
|
||||||
|
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE lessons DROP CONSTRAINT IF EXISTS lessons_requires_lesson_id_fkey;
|
||||||
|
ALTER TABLE lessons ADD CONSTRAINT lessons_requires_lesson_id_fkey
|
||||||
|
FOREIGN KEY (requires_lesson_id) REFERENCES lessons(id) ON DELETE SET NULL;
|
||||||
@@ -63,6 +63,9 @@ services:
|
|||||||
- --entrypoints.web.http.redirections.entrypoint.permanent=true
|
- --entrypoints.web.http.redirections.entrypoint.permanent=true
|
||||||
- --entrypoints.web.http.aliasHeadersStrategy=delete
|
- --entrypoints.web.http.aliasHeadersStrategy=delete
|
||||||
- --entrypoints.websecure.http.aliasHeadersStrategy=delete
|
- --entrypoints.websecure.http.aliasHeadersStrategy=delete
|
||||||
|
# Allow slow, large uploads (admin video ≤ 200MB); default is 60s.
|
||||||
|
- --entrypoints.web.transport.respondingTimeouts.readTimeout=3600
|
||||||
|
- --entrypoints.websecure.transport.respondingTimeouts.readTimeout=3600
|
||||||
# Dev: Traefik default certificate (browser warning expected on localhost).
|
# Dev: Traefik default certificate (browser warning expected on localhost).
|
||||||
- --api.dashboard=true
|
- --api.dashboard=true
|
||||||
- --api.insecure=true
|
- --api.insecure=true
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ services:
|
|||||||
- --entrypoints.web.http.redirections.entrypoint.permanent=true
|
- --entrypoints.web.http.redirections.entrypoint.permanent=true
|
||||||
- --entrypoints.web.http.aliasHeadersStrategy=delete
|
- --entrypoints.web.http.aliasHeadersStrategy=delete
|
||||||
- --entrypoints.websecure.http.aliasHeadersStrategy=delete
|
- --entrypoints.websecure.http.aliasHeadersStrategy=delete
|
||||||
|
# Allow slow, large uploads (admin video ≤ 200MB); default is 60s.
|
||||||
|
- --entrypoints.web.transport.respondingTimeouts.readTimeout=3600
|
||||||
|
- --entrypoints.websecure.transport.respondingTimeouts.readTimeout=3600
|
||||||
- --certificatesresolvers.le.acme.email=${ACME_EMAIL:?ACME_EMAIL must be set}
|
- --certificatesresolvers.le.acme.email=${ACME_EMAIL:?ACME_EMAIL must be set}
|
||||||
- --certificatesresolvers.le.acme.storage=/data/acme.json
|
- --certificatesresolvers.le.acme.storage=/data/acme.json
|
||||||
- --certificatesresolvers.le.acme.httpchallenge=true
|
- --certificatesresolvers.le.acme.httpchallenge=true
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ apiVersion: v2
|
|||||||
name: pargar
|
name: pargar
|
||||||
description: Pargar gated LMS - Go API, Next.js frontend, Postgres, Redis, S3-compatible storage
|
description: Pargar gated LMS - Go API, Next.js frontend, Postgres, Redis, S3-compatible storage
|
||||||
type: application
|
type: application
|
||||||
version: 0.2.2
|
version: 0.2.3
|
||||||
appVersion: "0.2.0"
|
appVersion: "0.2.1"
|
||||||
keywords:
|
keywords:
|
||||||
- lms
|
- lms
|
||||||
- pargar
|
- pargar
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
backend:
|
||||||
|
autoscaling:
|
||||||
|
enabled: false
|
||||||
|
env:
|
||||||
|
devMode: "false"
|
||||||
|
donationEnabled: "true"
|
||||||
|
otelEndpoint: http://tempo.infra.svc.cluster.local:4318
|
||||||
|
physicalCertEnabled: "false"
|
||||||
|
seedCurriculum: "false"
|
||||||
|
existingSecret: pargar-app
|
||||||
|
image:
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
repository: pargar-backend
|
||||||
|
tag: 0.2.1
|
||||||
|
metrics:
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: true
|
||||||
|
interval: 30s
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: true
|
||||||
|
minAvailable: 1
|
||||||
|
replicaCount: 3
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
backup:
|
||||||
|
enabled: true
|
||||||
|
persistence:
|
||||||
|
size: 2Gi
|
||||||
|
retentionDays: 7
|
||||||
|
schedule: 0 3 * * *
|
||||||
|
certManager:
|
||||||
|
enabled: false
|
||||||
|
frontend:
|
||||||
|
autoscaling:
|
||||||
|
enabled: false
|
||||||
|
image:
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
repository: pargar-frontend
|
||||||
|
tag: 0.2.1
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
replicaCount: 2
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
global:
|
||||||
|
domain: pargar.panahifar.ir
|
||||||
|
frontendOrigins: https://pargar.panahifar.ir
|
||||||
|
imageRegistry: ""
|
||||||
|
publicUrl: https://pargar.panahifar.ir
|
||||||
|
imagePullSecrets: []
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
tls:
|
||||||
|
enabled: true
|
||||||
|
existingSecret: pargar-wildcard-tls
|
||||||
|
useIngressRoute: true
|
||||||
|
networkPolicy:
|
||||||
|
enabled: false
|
||||||
|
postgres:
|
||||||
|
enabled: true
|
||||||
|
persistence:
|
||||||
|
size: 10Gi
|
||||||
|
redis:
|
||||||
|
enabled: true
|
||||||
|
persistence:
|
||||||
|
size: 2Gi
|
||||||
|
rustfs:
|
||||||
|
consoleEnable: false
|
||||||
|
enabled: true
|
||||||
|
persistence:
|
||||||
|
size: 20Gi
|
||||||
@@ -22,7 +22,7 @@ backend:
|
|||||||
replicaCount: 2
|
replicaCount: 2
|
||||||
image:
|
image:
|
||||||
repository: backend
|
repository: backend
|
||||||
tag: "0.2.0"
|
tag: "0.2.1"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
existingSecret: pargar-app
|
existingSecret: pargar-app
|
||||||
env:
|
env:
|
||||||
@@ -49,7 +49,7 @@ frontend:
|
|||||||
replicaCount: 2
|
replicaCount: 2
|
||||||
image:
|
image:
|
||||||
repository: frontend
|
repository: frontend
|
||||||
tag: "0.2.0"
|
tag: "0.2.1"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# k3s Traefik customisation (HelmChartConfig for the built-in `traefik` chart).
|
||||||
|
#
|
||||||
|
# Apply with: kubectl apply -f deploy/k3s/traefik-helmchartconfig.yaml
|
||||||
|
#
|
||||||
|
# Why: Traefik's entrypoint `readTimeout` defaults to 60s and covers reading the
|
||||||
|
# *entire request including the body*. Admin video uploads (up to 200MB) that take
|
||||||
|
# longer than 60s were cut off with a 502 before reaching the backend. Raise it to
|
||||||
|
# 1 hour (use 0 to disable entirely).
|
||||||
|
apiVersion: helm.cattle.io/v1
|
||||||
|
kind: HelmChartConfig
|
||||||
|
metadata:
|
||||||
|
name: traefik
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
failurePolicy: reinstall
|
||||||
|
valuesContent: |-
|
||||||
|
# ACCESSLOG tile -> ON; access logs go to container stdout (kubectl logs).
|
||||||
|
# Key is logs.access.enabled on the chart k3s ships (40.1.5);
|
||||||
|
# the top-level accessLog.enabled only exists on newer chart versions.
|
||||||
|
logs:
|
||||||
|
access:
|
||||||
|
enabled: true
|
||||||
|
# Allow IngressRoutes to reference Services living in other namespaces,
|
||||||
|
# e.g. argocd-server in `argocd`.
|
||||||
|
providers:
|
||||||
|
kubernetesCRD:
|
||||||
|
allowCrossNamespace: true
|
||||||
|
deployment:
|
||||||
|
podAnnotations:
|
||||||
|
# fix: metrics entrypoint listens on :9100, annotation said 8082
|
||||||
|
prometheus.io/port: "9100"
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
# Allow slow, large uploads (admin video upload ≤ 200MB) to finish.
|
||||||
|
# Default is 60s; 3600s = 1h. Set to 0 to disable the cap.
|
||||||
|
ports:
|
||||||
|
web:
|
||||||
|
transport:
|
||||||
|
respondingTimeouts:
|
||||||
|
readTimeout: 3600
|
||||||
|
websecure:
|
||||||
|
transport:
|
||||||
|
respondingTimeouts:
|
||||||
|
readTimeout: 3600
|
||||||
Reference in New Issue
Block a user