From 6f7263dd842132213e0e22d999a36f283b071576 Mon Sep 17 00:00:00 2001 From: ngn Date: Fri, 17 Jan 2025 02:42:32 +0300 Subject: [PATCH] finish up the documentation page Signed-off-by: ngn --- api/database/metrics.go | 2 +- api/routes/metrics.go | 32 +- app/package-lock.json | 2 + app/package.json | 1 + app/src/lib/doc.js | 2 +- app/src/lib/footer.svelte | 4 +- app/src/lib/util.js | 15 +- app/src/locales/en.json | 4 +- app/src/locales/tr.json | 4 +- app/src/routes/+layout.js | 2 +- app/src/routes/doc/[name]/+page.js | 11 - app/src/routes/doc/[name]/+page.server.js | 9 + app/src/routes/doc/[name]/+page.svelte | 50 +- doc/docs/api.en.json | 4 + doc/docs/{api.md => api.en.md} | 46 +- doc/docs/api.json | 4 - doc/docs/api.tr.json | 4 + doc/docs/api.tr.md | 159 +++++ doc/docs/{license.json => license.en.json} | 0 doc/docs/{license.md => license.en.md} | 0 doc/docs/license.tr.json | 4 + doc/docs/license.tr.md | 675 +++++++++++++++++++++ doc/inc/docs.h | 18 + doc/inc/util.h | 8 +- doc/src/docs.c | 106 ++++ doc/src/routes/get.c | 96 ++- doc/src/routes/list.c | 85 +-- doc/src/util.c | 28 +- 28 files changed, 1141 insertions(+), 234 deletions(-) delete mode 100644 app/src/routes/doc/[name]/+page.js create mode 100644 app/src/routes/doc/[name]/+page.server.js create mode 100644 doc/docs/api.en.json rename doc/docs/{api.md => api.en.md} (69%) delete mode 100644 doc/docs/api.json create mode 100644 doc/docs/api.tr.json create mode 100644 doc/docs/api.tr.md rename doc/docs/{license.json => license.en.json} (100%) rename doc/docs/{license.md => license.en.md} (100%) create mode 100644 doc/docs/license.tr.json create mode 100644 doc/docs/license.tr.md create mode 100644 doc/inc/docs.h create mode 100644 doc/src/docs.c diff --git a/api/database/metrics.go b/api/database/metrics.go index 959d4dc..22ae9b5 100644 --- a/api/database/metrics.go +++ b/api/database/metrics.go @@ -44,7 +44,7 @@ func (db *Type) MetricsSet(key string, value uint64) error { return err } else if effected < 1 { _, err = db.sql.Exec( - `INSERT INTO "+TABLE_METRICS+"( + "INSERT INTO "+TABLE_METRICS+`( key, value ) values(?, ?)`, key, value, diff --git a/api/routes/metrics.go b/api/routes/metrics.go index fc91c48..728cab7 100644 --- a/api/routes/metrics.go +++ b/api/routes/metrics.go @@ -8,30 +8,25 @@ import ( "github.com/ngn13/website/api/util" ) -type visitor_cache_entry struct { - Addr string // SHA1 hash of visitor's IP - Number uint64 // number of the visitor -} - -const VISITOR_CACHE_MAX = 30 // store 30 visitor data at most -var visitor_cache []visitor_cache_entry // in memory cache for the visitor +const VISITOR_CACHE_MAX = 30 // store 30 visitor data at most +var visitor_cache []string // in memory cache for the visitor addresses func GET_Metrics(c *fiber.Ctx) error { var ( err error result map[string]uint64 = map[string]uint64{ - "number": 0, // visitor number of the current visitor - "total": 0, // total number of visitors - "since": 0, // metric collection start date (UNIX timestamp) + "total": 0, // total number of visitors + "since": 0, // metric collection start date (UNIX timestamp) } ) db := c.Locals("database").(*database.Type) new_addr := util.GetSHA1(util.IP(c)) + is_in_cache := false - for i := range visitor_cache { - if new_addr == visitor_cache[i].Addr { - result["number"] = visitor_cache[i].Number + for _, cache := range visitor_cache { + if new_addr == cache { + is_in_cache = true break } } @@ -40,19 +35,14 @@ func GET_Metrics(c *fiber.Ctx) error { return util.ErrInternal(c, err) } - if result["number"] == 0 { - result["total"]++ - result["number"] = result["total"] - + if !is_in_cache { if len(visitor_cache) > VISITOR_CACHE_MAX { util.Debg("visitor cache is full, removing the oldest entry") visitor_cache = visitor_cache[1:] } - visitor_cache = append(visitor_cache, visitor_cache_entry{ - Addr: new_addr, - Number: result["number"], - }) + visitor_cache = append(visitor_cache, new_addr) + result["total"]++ if err = db.MetricsSet("visitor_count", result["total"]); err != nil { return util.ErrInternal(c, err) diff --git a/app/package-lock.json b/app/package-lock.json index d8ac382..2a50ba2 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -9,6 +9,7 @@ "version": "6.0", "dependencies": { "@types/dompurify": "^3.2.0", + "dompurify": "^3.2.3", "marked": "^15.0.6", "svelte-i18n": "^4.0.1" }, @@ -1092,6 +1093,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz", "integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==", + "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" } diff --git a/app/package.json b/app/package.json index d1f763a..cee0f74 100644 --- a/app/package.json +++ b/app/package.json @@ -22,6 +22,7 @@ "type": "module", "dependencies": { "@types/dompurify": "^3.2.0", + "dompurify": "^3.2.3", "marked": "^15.0.6", "svelte-i18n": "^4.0.1" } diff --git a/app/src/lib/doc.js b/app/src/lib/doc.js index e1a29ca..fa9bbb8 100644 --- a/app/src/lib/doc.js +++ b/app/src/lib/doc.js @@ -16,7 +16,7 @@ async function doc_http_get(fetch, url) { } async function doc_get_list(fetch) { - return (await doc_http_get(fetch, doc_urljoin("/list")))["list"]; + return await doc_http_get(fetch, doc_urljoin("/list")); } async function doc_get(fetch, name) { diff --git a/app/src/lib/footer.svelte b/app/src/lib/footer.svelte index f4b365d..691771c 100644 --- a/app/src/lib/footer.svelte +++ b/app/src/lib/footer.svelte @@ -40,12 +40,12 @@ {$_("footer.number", { values: { - number: data.number, + total: data.total, since: date_from_ts(data.since), }, })} {#if data.number % 1000 == 0} - ({$_("footer.congrat")}) + ({$_("footer.wow")}) {/if} diff --git a/app/src/lib/util.js b/app/src/lib/util.js index c123b21..c70e174 100644 --- a/app/src/lib/util.js +++ b/app/src/lib/util.js @@ -23,20 +23,23 @@ function browser_lang() { function set_lang(lang) { language.set(default_language); + locale.set(default_language); if (lang === null || lang === undefined) { - if (browser) set_lang(browser_lang()); + if (browser && null !== (lang = localStorage.getItem("language"))) set_lang(lang); + else if (browser) set_lang(browser_lang()); return; } lang = lang.slice(0, 2); for (let i = 0; i < languages.length; i++) { - if (lang === languages[i].code) { - language.set(lang); - locale.set(lang); - return; - } + if (lang !== languages[i].code) continue; + + language.set(lang); + locale.set(lang); + + if (browser) localStorage.setItem("language", lang); } } diff --git a/app/src/locales/en.json b/app/src/locales/en.json index 36e1e39..e18fd24 100644 --- a/app/src/locales/en.json +++ b/app/src/locales/en.json @@ -76,8 +76,8 @@ "license": "License", "privacy": "Privacy", "powered": "Powered by Svelte, Go, SQLite and donations", - "number": "You are the visitor number {number} since {since}", - "congrat": "congrats!!", + "number": "Visited {total} times since {since}", + "wow": "wow!!", "version": "Using API version {api_version}, frontend version {frontend_version}" } } diff --git a/app/src/locales/tr.json b/app/src/locales/tr.json index 3d0fedd..9280bf7 100644 --- a/app/src/locales/tr.json +++ b/app/src/locales/tr.json @@ -77,8 +77,8 @@ "license": "Lisans", "privacy": "Gizlilik", "powered": "Svelte, Go, SQLite ve bağışlar tarafından destekleniyor", - "number": "{since} tarihinden beri {number}. ziyaretçisiniz", - "congrat": "tebrikler!!", + "number": "{since} tarihinden beri {total} kez ziyaret edildi", + "wow": "vay be!!", "version": "Kullan API versiyonu {api_version}, arayüz versiyonu {frontend_version}" } } diff --git a/app/src/routes/+layout.js b/app/src/routes/+layout.js index 471e781..bd85af2 100644 --- a/app/src/routes/+layout.js +++ b/app/src/routes/+layout.js @@ -31,7 +31,7 @@ export async function load({ fetch }) { }; } catch (err) { return { - error: err, + error: err.toString(), }; } } diff --git a/app/src/routes/doc/[name]/+page.js b/app/src/routes/doc/[name]/+page.js deleted file mode 100644 index 995acae..0000000 --- a/app/src/routes/doc/[name]/+page.js +++ /dev/null @@ -1,11 +0,0 @@ -import { goto } from "$app/navigation"; -import { doc_get } from "$lib/doc"; - -export async function load({ fetch, params }) { - try { - return await doc_get(fetch, params.name); - } catch (err) { - if (err.toString().includes("not found")) return goto("/"); - return { error: err }; - } -} diff --git a/app/src/routes/doc/[name]/+page.server.js b/app/src/routes/doc/[name]/+page.server.js new file mode 100644 index 0000000..3a7bd5e --- /dev/null +++ b/app/src/routes/doc/[name]/+page.server.js @@ -0,0 +1,9 @@ +import { doc_get } from "$lib/doc"; + +export async function load({ fetch, params }) { + try { + return { doc: await doc_get(fetch, params.name) }; + } catch (err) { + return { error: err.toString() }; + } +} diff --git a/app/src/routes/doc/[name]/+page.svelte b/app/src/routes/doc/[name]/+page.svelte index b8e80ab..cc5ac4c 100644 --- a/app/src/routes/doc/[name]/+page.svelte +++ b/app/src/routes/doc/[name]/+page.svelte @@ -2,36 +2,48 @@ import Header from "$lib/header.svelte"; import Head from "$lib/head.svelte"; - import { color } from "$lib/util.js"; + import { language, color } from "$lib/util.js"; + import { goto } from "$app/navigation"; + import DOMPurify from "dompurify"; + import { onMount } from "svelte"; import { marked } from "marked"; import { _ } from "svelte-i18n"; let { data } = $props(); marked.use({ breaks: true }); + + onMount(async () => { + if (data.error !== null) return await goto("/"); + + for (let key in data.doc) + data.doc[key]["content"] = DOMPurify.sanitize(data.doc[key]["content"]); + });
-
- {@html marked.parse(data.content)} -
-
- {#each data.docs as doc} - {#if doc.title == data.title} - -

{doc.title}

-

{doc.desc}

-
- {:else} - -

{doc.title}

-

{doc.desc}

-
- {/if} - {/each} -
+ {#if data.doc !== undefined} +
+ {@html marked.parse(data.doc[$language].content)} +
+
+ {#each data.docs[$language] as doc} + {#if doc.title == data.doc[$language].title} + +

{doc.title}

+

{doc.desc}

+
+ {:else} + +

{doc.title}

+

{doc.desc}

+
+ {/if} + {/each} +
+ {/if}