This commit is contained in:
@@ -92,6 +92,20 @@ jobs:
|
|||||||
rm -f /tmp/backend-deploy.tar.gz
|
rm -f /tmp/backend-deploy.tar.gz
|
||||||
REMOTE
|
REMOTE
|
||||||
|
|
||||||
|
- name: Free disk on deploy host (docker prune)
|
||||||
|
run: |
|
||||||
|
ssh deploy-target bash -s <<REMOTE
|
||||||
|
set -euo pipefail
|
||||||
|
PRUNE="${REMOTE_BACKEND}/scripts/docker-prune.sh"
|
||||||
|
if [[ -x "\${PRUNE}" ]]; then
|
||||||
|
bash "\${PRUNE}"
|
||||||
|
else
|
||||||
|
sudo docker builder prune -af || true
|
||||||
|
sudo docker system prune -af || true
|
||||||
|
df -h /
|
||||||
|
fi
|
||||||
|
REMOTE
|
||||||
|
|
||||||
- name: Rebuild and restart API container
|
- name: Rebuild and restart API container
|
||||||
run: |
|
run: |
|
||||||
ssh deploy-target bash -s <<REMOTE
|
ssh deploy-target bash -s <<REMOTE
|
||||||
|
|||||||
@@ -36,8 +36,57 @@ func requestLangCode(r *http.Request) string {
|
|||||||
return translateNormalizePostLang(raw)
|
return translateNormalizePostLang(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t postTextI18n) pick(r *http.Request) string {
|
// textForLang returns body text stored for the post's source language only.
|
||||||
return pickLangField(r, t.TextZh, t.TextEn, t.TextJa, t.TextKo, t.TextVi, t.TextId, t.TextMs)
|
func (t postTextI18n) textForLang(lang string) string {
|
||||||
|
switch translateNormalizePostLang(lang) {
|
||||||
|
case "en":
|
||||||
|
return strings.TrimSpace(t.TextEn)
|
||||||
|
case "ja":
|
||||||
|
return strings.TrimSpace(t.TextJa)
|
||||||
|
case "ko":
|
||||||
|
return strings.TrimSpace(t.TextKo)
|
||||||
|
case "vi":
|
||||||
|
return strings.TrimSpace(t.TextVi)
|
||||||
|
case "id":
|
||||||
|
return strings.TrimSpace(t.TextId)
|
||||||
|
case "ms":
|
||||||
|
return strings.TrimSpace(t.TextMs)
|
||||||
|
default:
|
||||||
|
return strings.TrimSpace(t.TextZh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func postTextI18nFromSingle(lang, text string) postTextI18n {
|
||||||
|
lang = translateNormalizePostLang(lang)
|
||||||
|
text = strings.TrimSpace(text)
|
||||||
|
var t postTextI18n
|
||||||
|
switch lang {
|
||||||
|
case "en":
|
||||||
|
t.TextEn = text
|
||||||
|
case "ja":
|
||||||
|
t.TextJa = text
|
||||||
|
case "ko":
|
||||||
|
t.TextKo = text
|
||||||
|
case "vi":
|
||||||
|
t.TextVi = text
|
||||||
|
case "id":
|
||||||
|
t.TextId = text
|
||||||
|
case "ms":
|
||||||
|
t.TextMs = text
|
||||||
|
default:
|
||||||
|
t.TextZh = text
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizePostSourceLang(lang string) string {
|
||||||
|
lang = translateNormalizePostLang(strings.TrimSpace(lang))
|
||||||
|
switch lang {
|
||||||
|
case "zh", "en", "ja", "ko", "vi", "id", "ms":
|
||||||
|
return lang
|
||||||
|
default:
|
||||||
|
return "zh"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t postTextI18n) anyNonEmpty() bool {
|
func (t postTextI18n) anyNonEmpty() bool {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type PostDTO struct {
|
|||||||
Language string `json:"language"` // UI locale from ?lang= (matches text selection)
|
Language string `json:"language"` // UI locale from ?lang= (matches text selection)
|
||||||
SourceLanguage string `json:"sourceLanguage,omitempty"` // DB source metadata (admin input language)
|
SourceLanguage string `json:"sourceLanguage,omitempty"` // DB source metadata (admin input language)
|
||||||
Text string `json:"text,omitempty"`
|
Text string `json:"text,omitempty"`
|
||||||
Localizations map[string]postLocalePayload `json:"localizations"`
|
Localizations map[string]postLocalePayload `json:"localizations,omitempty"`
|
||||||
Attachments []AttachmentDTO `json:"attachments"`
|
Attachments []AttachmentDTO `json:"attachments"`
|
||||||
IsRecommended bool `json:"isRecommended"`
|
IsRecommended bool `json:"isRecommended"`
|
||||||
PublishedAt string `json:"publishedAt"`
|
PublishedAt string `json:"publishedAt"`
|
||||||
@@ -439,10 +439,10 @@ func scanPostRow(r *http.Request, row pgx.Row) (PostDTO, postTextI18n, error) {
|
|||||||
if slug != nil {
|
if slug != nil {
|
||||||
dto.CategorySlug = *slug
|
dto.CategorySlug = *slug
|
||||||
}
|
}
|
||||||
dto.SourceLanguage = sourceLang
|
src := normalizePostSourceLang(sourceLang)
|
||||||
dto.Language = requestLangCode(r)
|
dto.SourceLanguage = src
|
||||||
dto.Text = texts.pick(r)
|
dto.Language = src
|
||||||
dto.Localizations = texts.toLocalizations()
|
dto.Text = texts.textForLang(src)
|
||||||
if pub != nil {
|
if pub != nil {
|
||||||
dto.PublishedAt = pub.UTC().Format(time.RFC3339)
|
dto.PublishedAt = pub.UTC().Format(time.RFC3339)
|
||||||
} else if created != nil {
|
} else if created != nil {
|
||||||
|
|||||||
@@ -127,6 +127,9 @@ func listPostsQuery(w http.ResponseWriter, r *http.Request, searchMode bool) {
|
|||||||
typ = "all"
|
typ = "all"
|
||||||
}
|
}
|
||||||
langFilter := strings.TrimSpace(r.URL.Query().Get("language"))
|
langFilter := strings.TrimSpace(r.URL.Query().Get("language"))
|
||||||
|
if langFilter == "" {
|
||||||
|
langFilter = strings.TrimSpace(r.URL.Query().Get("lang"))
|
||||||
|
}
|
||||||
|
|
||||||
base := postSelectBase() + ` WHERE ` + publicPostWhere
|
base := postSelectBase() + ` WHERE ` + publicPostWhere
|
||||||
args := []any{}
|
args := []any{}
|
||||||
|
|||||||
38
scripts/docker-prune.sh
Executable file
38
scripts/docker-prune.sh
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Free disk before docker compose build (build cache is the usual culprit for Go OOM / no space).
|
||||||
|
# Safe on deploy hosts: does NOT use --volumes (keeps named DB volumes).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
docker_cmd() {
|
||||||
|
if docker info >/dev/null 2>&1; then
|
||||||
|
docker "$@"
|
||||||
|
elif sudo docker info >/dev/null 2>&1; then
|
||||||
|
sudo docker "$@"
|
||||||
|
else
|
||||||
|
echo "docker not available — skip prune" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "==> disk before prune"
|
||||||
|
df -h / 2>/dev/null || true
|
||||||
|
if [[ -d /var/lib/docker ]]; then
|
||||||
|
df -h /var/lib/docker 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! docker info >/dev/null 2>&1 && ! sudo docker info >/dev/null 2>&1; then
|
||||||
|
echo "docker not available — skip prune" >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> docker builder prune (build cache)"
|
||||||
|
docker_cmd builder prune -af || true
|
||||||
|
|
||||||
|
echo "==> docker system prune (unused images, stopped containers, networks)"
|
||||||
|
docker_cmd system prune -af || true
|
||||||
|
|
||||||
|
echo "==> disk after prune"
|
||||||
|
df -h / 2>/dev/null || true
|
||||||
|
if [[ -d /var/lib/docker ]]; then
|
||||||
|
df -h /var/lib/docker 2>/dev/null || true
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user