@@ -46,36 +46,11 @@ type ResourceDTO struct {
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
func pickLangName(r *http.Request, zhTW, zhCN, en string) string {
|
||||
lang := strings.TrimSpace(r.URL.Query().Get("lang"))
|
||||
if lang == "" {
|
||||
lang = r.Header.Get("Accept-Language")
|
||||
}
|
||||
lang = strings.ToLower(strings.TrimSpace(strings.Split(lang, ",")[0]))
|
||||
switch {
|
||||
case strings.HasPrefix(lang, "zh-cn") || lang == "zh-hans":
|
||||
if zhCN != "" {
|
||||
return zhCN
|
||||
}
|
||||
case strings.HasPrefix(lang, "en"):
|
||||
if en != "" {
|
||||
return en
|
||||
}
|
||||
}
|
||||
if zhTW != "" {
|
||||
return zhTW
|
||||
}
|
||||
if zhCN != "" {
|
||||
return zhCN
|
||||
}
|
||||
return en
|
||||
}
|
||||
|
||||
func ListCategories(w http.ResponseWriter, r *http.Request) {
|
||||
pool := poolFrom(r)
|
||||
rows, err := pool.Query(r.Context(), `
|
||||
SELECT id, slug, name_zh_tw, name_zh_cn, name_en, description_zh_tw, icon_key, sort_order, updated_at
|
||||
FROM categories WHERE is_visible = TRUE ORDER BY sort_order ASC, id ASC`)
|
||||
SELECT c.id, c.slug, `+categoryI18nColsSQL+`, c.icon_key, c.sort_order, c.updated_at
|
||||
FROM categories c WHERE c.is_visible = TRUE ORDER BY c.sort_order ASC, c.id ASC`)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@@ -84,15 +59,19 @@ func ListCategories(w http.ResponseWriter, r *http.Request) {
|
||||
out := make([]CategoryDTO, 0)
|
||||
for rows.Next() {
|
||||
var c CategoryDTO
|
||||
var zhTW, zhCN, en *string
|
||||
var desc *string
|
||||
var nameZh, nameEn, nameJa, nameKo, nameVi, nameId, nameMs string
|
||||
var descZh, descEn, descJa, descKo, descVi, descId, descMs string
|
||||
var updated time.Time
|
||||
if err := rows.Scan(&c.ID, &c.Slug, &zhTW, &zhCN, &en, &desc, &c.IconKey, &c.SortOrder, &updated); err != nil {
|
||||
if err := rows.Scan(&c.ID, &c.Slug,
|
||||
&nameZh, &nameEn, &nameJa, &nameKo, &nameVi, &nameId, &nameMs,
|
||||
&descZh, &descEn, &descJa, &descKo, &descVi, &descId, &descMs,
|
||||
&c.IconKey, &c.SortOrder, &updated); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
c.Name = pickLangName(r, deref(zhTW), deref(zhCN), deref(en))
|
||||
c.Description = deref(desc)
|
||||
texts := scanCategoryTextI18n(nameZh, nameEn, nameJa, nameKo, nameVi, nameId, nameMs, descZh, descEn, descJa, descKo, descVi, descId, descMs)
|
||||
c.Name = texts.pickName(r)
|
||||
c.Description = texts.pickDesc(r)
|
||||
c.UpdatedAt = updated.UTC().Format(time.RFC3339)
|
||||
out = append(out, c)
|
||||
}
|
||||
@@ -138,7 +117,7 @@ func ListResources(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
base := `
|
||||
SELECT r.id, ` + resourceI18nColsSQL + `, r.type, COALESCE(r.language,'zh-TW'), r.category_id, c.slug, c.name_zh_tw, c.name_zh_cn, c.name_en,
|
||||
SELECT r.id, ` + resourceI18nColsSQL + `, r.type, COALESCE(r.language,'zh'), r.category_id, c.slug, ` + categoryNameColsSQL + `,
|
||||
COALESCE(r.cover_image,''), COALESCE(r.file_url,''), COALESCE(r.preview_url,''), COALESCE(r.external_url,''), COALESCE(r.badge_label,''),
|
||||
r.is_downloadable, r.is_recommended, r.published_at, r.updated_at
|
||||
FROM resources r JOIN categories c ON c.id = r.category_id
|
||||
@@ -159,10 +138,12 @@ func ListResources(w http.ResponseWriter, r *http.Request) {
|
||||
start := len(args) + 1
|
||||
args = append(args, pat)
|
||||
cond += fmt.Sprintf(` AND (
|
||||
r.title_zh_tw ILIKE $%d OR r.title_zh_cn ILIKE $%d OR r.title_en ILIKE $%d OR
|
||||
r.description_zh_tw ILIKE $%d OR r.description_zh_cn ILIKE $%d OR r.description_en ILIKE $%d OR
|
||||
r.title_zh ILIKE $%d OR r.title_en ILIKE $%d OR r.title_ja ILIKE $%d OR r.title_ko ILIKE $%d OR
|
||||
r.title_vi ILIKE $%d OR r.title_id ILIKE $%d OR r.title_ms ILIKE $%d OR
|
||||
r.description_zh ILIKE $%d OR r.description_en ILIKE $%d OR r.description_ja ILIKE $%d OR
|
||||
r.description_ko ILIKE $%d OR r.description_vi ILIKE $%d OR r.description_id ILIKE $%d OR r.description_ms ILIKE $%d OR
|
||||
EXISTS (SELECT 1 FROM resource_tags rt JOIN tags t ON t.id = rt.tag_id WHERE rt.resource_id = r.id AND t.name ILIKE $%d))`,
|
||||
start, start, start, start, start, start, start)
|
||||
start, start, start, start, start, start, start, start, start, start, start, start, start, start, start)
|
||||
}
|
||||
tag := strings.TrimSpace(r.URL.Query().Get("tag"))
|
||||
if tag != "" {
|
||||
@@ -217,7 +198,7 @@ func listFeatured(w http.ResponseWriter, r *http.Request, extra string, order st
|
||||
limit = 50
|
||||
}
|
||||
sqlStr := `
|
||||
SELECT r.id, ` + resourceI18nColsSQL + `, r.type, COALESCE(r.language,'zh-TW'), r.category_id, c.slug, c.name_zh_tw, c.name_zh_cn, c.name_en,
|
||||
SELECT r.id, ` + resourceI18nColsSQL + `, r.type, COALESCE(r.language,'zh'), r.category_id, c.slug, ` + categoryNameColsSQL + `,
|
||||
COALESCE(r.cover_image,''), COALESCE(r.file_url,''), COALESCE(r.preview_url,''), COALESCE(r.external_url,''), COALESCE(r.badge_label,''),
|
||||
r.is_downloadable, r.is_recommended, r.published_at, r.updated_at
|
||||
FROM resources r JOIN categories c ON c.id = r.category_id
|
||||
@@ -247,7 +228,7 @@ func GetResource(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
row := pool.QueryRow(r.Context(), `
|
||||
SELECT r.id, `+resourceI18nColsSQL+`, r.type, COALESCE(r.language,'zh-TW'), r.category_id, c.slug, c.name_zh_tw, c.name_zh_cn, c.name_en,
|
||||
SELECT r.id, `+resourceI18nColsSQL+`, r.type, COALESCE(r.language,'zh'), r.category_id, c.slug, `+categoryNameColsSQL+`,
|
||||
COALESCE(r.cover_image,''), COALESCE(r.file_url,''), COALESCE(r.preview_url,''), COALESCE(r.external_url,''), COALESCE(r.badge_label,''),
|
||||
r.is_downloadable, r.is_recommended, r.published_at, r.updated_at
|
||||
FROM resources r JOIN categories c ON c.id = r.category_id
|
||||
@@ -278,7 +259,7 @@ func RelatedResources(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
rows, err := pool.Query(r.Context(), `
|
||||
SELECT r.id, `+resourceI18nColsSQL+`, r.type, COALESCE(r.language,'zh-TW'), r.category_id, c.slug, c.name_zh_tw, c.name_zh_cn, c.name_en,
|
||||
SELECT r.id, `+resourceI18nColsSQL+`, r.type, COALESCE(r.language,'zh'), r.category_id, c.slug, `+categoryNameColsSQL+`,
|
||||
COALESCE(r.cover_image,''), COALESCE(r.file_url,''), COALESCE(r.preview_url,''), COALESCE(r.external_url,''), COALESCE(r.badge_label,''),
|
||||
r.is_downloadable, r.is_recommended, r.published_at, r.updated_at
|
||||
FROM resources r JOIN categories c ON c.id = r.category_id
|
||||
@@ -404,15 +385,16 @@ func scanResourceRow(scanner interface {
|
||||
var dto ResourceDTO
|
||||
var pubAt *time.Time
|
||||
var updated time.Time
|
||||
var zhTW, zhCN, en *string
|
||||
var catNameZh, catNameEn, catNameJa, catNameKo, catNameVi, catNameId, catNameMs string
|
||||
var id uuid.UUID
|
||||
var texts resourceTextI18n
|
||||
err := scanner.Scan(
|
||||
&id,
|
||||
&texts.TitleZhTw, &texts.TitleZhCn, &texts.TitleEn,
|
||||
&texts.DescZhTw, &texts.DescZhCn, &texts.DescEn,
|
||||
&texts.BodyZhTw, &texts.BodyZhCn, &texts.BodyEn,
|
||||
&dto.Type, &dto.Language, &dto.CategoryID, &dto.CategorySlug, &zhTW, &zhCN, &en,
|
||||
&texts.TitleZh, &texts.TitleEn, &texts.TitleJa, &texts.TitleKo, &texts.TitleVi, &texts.TitleId, &texts.TitleMs,
|
||||
&texts.DescZh, &texts.DescEn, &texts.DescJa, &texts.DescKo, &texts.DescVi, &texts.DescId, &texts.DescMs,
|
||||
&texts.BodyZh, &texts.BodyEn, &texts.BodyJa, &texts.BodyKo, &texts.BodyVi, &texts.BodyId, &texts.BodyMs,
|
||||
&dto.Type, &dto.Language, &dto.CategoryID, &dto.CategorySlug,
|
||||
&catNameZh, &catNameEn, &catNameJa, &catNameKo, &catNameVi, &catNameId, &catNameMs,
|
||||
&dto.CoverImage, &dto.FileURL, &dto.PreviewURL, &dto.ExternalURL, &dto.BadgeLabel,
|
||||
&dto.IsDownloadable, &dto.IsRecommended, &pubAt, &updated,
|
||||
)
|
||||
@@ -421,7 +403,8 @@ func scanResourceRow(scanner interface {
|
||||
}
|
||||
dto.ID = id.String()
|
||||
dto.Title, dto.Description, dto.BodyText = texts.pick(r)
|
||||
dto.CategoryName = pickLangName(r, deref(zhTW), deref(zhCN), deref(en))
|
||||
catTexts := categoryTextI18n{NameZh: catNameZh, NameEn: catNameEn, NameJa: catNameJa, NameKo: catNameKo, NameVi: catNameVi, NameId: catNameId, NameMs: catNameMs}
|
||||
dto.CategoryName = catTexts.pickName(r)
|
||||
if pubAt != nil {
|
||||
s := pubAt.UTC().Format(time.RFC3339)
|
||||
dto.PublishedAt = &s
|
||||
|
||||
Reference in New Issue
Block a user