diff --git a/CHANGELOG.md b/CHANGELOG.md index 40264af..366a6d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,45 +1,30 @@ # Changelog This file keeps track of changes in a human-readable fashion -## Upcoming -These changes were not yet released - -* Adjusted default theme -* Error pages are now translated - ## v1.1.4 - * Fixed HTML `lang` tag * Theme CSS link is now only present if non-default is set * Improved template consistency (backend) ## v1.1.3 - This release mostly consists of backend improvements * List items no longer replace hyphens with spaces for consistency * Telegram message for SCRAM is now translatable * Ensured HTML escape in list descriptions * Refactored many methods, improved comments - ## v1.1.2 - This release contains a few bug fixes * Real IPs are now logged (By Rithas K.) * CSS now has `box-sizing: border-box` to fix textarea in some cases (By Rithas K.) * Done some minor code housekeeping - ## v1.1.1 - This release is mostly a technicality, with a move over to GitHub (`ghcr.io/andrew-71/hibiscus`) for packages due to DockerHub's prior anti-Russian actions making old "CI/CD" unsustainable. - ## v1.1.0 - * You can now specify the Telegram *topic* to send notification to via `tg_topic` config key (By Rithas K.) * The Telegram message is now partially translated * Fixed CSS `margin` and `text-align` inherited from my website ## v1.0.0 - This release includes several **breaking** changes * Made a new favicon * English is now used as a fallback language, making incomplete translations somewhat usable @@ -53,20 +38,16 @@ This release includes several **breaking** changes * Comic Sans MS for *everything* * sorry -## v0.6.1 - -* Fixed date display when using `Local` timezone - ## v0.6.0 - * Replaced config reload with edit in info (api method still available, config reloads on save) * Bug fixes * Filenames are now sanitized when writing files * "Tomorrow" in days list is now also displayed if Timezone is changed and grace period is off * Frontend date display now uses configured timezone +### v0.6.1 +* Fixed date display when using `Local` timezone ## v0.5.0 - * Added a JS prompt to create new note * "Sanitization" for this method is basic and assumes a well-meaning user * Old instructions appear if JS is disabled @@ -75,7 +56,6 @@ This release includes several **breaking** changes * Config reload now sets removed values to defaults ## v0.4.0 - * Customisation changes * Added `title` option to config * Controls the text in the header, "🌺 Hibiscus.txt" by default @@ -86,20 +66,17 @@ This release includes several **breaking** changes * Spaces in config options are now supported (basically just for `title`) ## v0.3.0 - * Added themes * Picked theme is set by `theme` key in config. Default is ...`default` * Themes are defined in `/public/themes/.css` and modify colours (or, theoretically, do more) * Current pre-made themes are `default`, `gruvbox` and `high-contrast` ## v0.2.0 - * Added config reload * Can be reloaded in info page * Can be reloaded with new `reload` api method (be aware of the redirect if referer is present) ## 7 May 2024 - v0.1.0 - * Began move towards [semantic versioning](https://semver.org/) * Current version is now 0.1.0 * Added `version` api method @@ -114,7 +91,6 @@ This release includes several **breaking** changes * Fixed export function failing ## 6 May 2024 - * Grace period is now non-inclusive (so `4h` means the switch will happen right at `4:00`, not `4:01`) * Added API method to check if grace period is active * Made changes to date display on frontend @@ -124,7 +100,6 @@ This release includes several **breaking** changes But I think it's fine. ## 5 May 2024 - * Added this changelog * Added grace period (as per suggestions) * Set in config like `grace_period=3h26m` (via Go's `time.ParseDuration`) diff --git a/Makefile b/Makefile deleted file mode 100644 index 51564d3..0000000 --- a/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -build: - go build - -run: - go build & ./hibiscus-txt - -dev: - go build & ./hibiscus-txt --config config/dev-config.txt \ No newline at end of file diff --git a/README.md b/README.md index de0c9b6..46674fa 100644 --- a/README.md +++ b/README.md @@ -6,27 +6,22 @@ This project is *very* opinionated and minimal, and is designed primarily for my As a result, I can't guarantee that it's either secure or stable. ## Features: - * Each day, you get a new text file. You have until the end of that very day to finalise it. * You can save named notes to document milestones, big events, or just a nice game you played this month * You can easily export the files in a `.zip` archive for backups -* Everything is plain(text) and simple. -No databases, encryption, OAuth, or anything fancy. Even the password is plainte- *wait is this a feature?* -* [Docker support](#docker-deployment) +* Everything is plain(text) and simple. No databases, encryption, OAuth, or anything fancy. Even the password is plainte- *wait is this a feature?* +* [Docker support](#docker-deployment) (in fact, that's probably the best way to run this) * Optional Telegram notifications for failed login attempts ## Technical details +[CHANGELOG.md](./CHANGELOG.md) provides a good overview of updates, and [TODO.md](./TODO.md) file shows what I will (or *may*) work on in the future. -[CHANGELOG.md](./CHANGELOG.md) provides a good overview of updates, and [TODO.md](./TODO.md) file shows my plans for the future. - -You can read a relevant entry in my blog [here](https://a71.su/notes/hibiscus/). +You can read a relevant entry in my blog [here](https://a71.su/notes/hibiscus/). It provides some useful information and context for why this app exists in the first place. -This repository is [self-hosted by me](https://git.a71.su/Andrew71/hibiscus), -but [mirrored to GitHub](https://github.com/Andrew-71/hibiscus). +This repository is [self-hosted by me](https://git.a71.su/Andrew71/hibiscus), but [mirrored to GitHub](https://github.com/Andrew-71/hibiscus) in case my server goes down. ### Data format: - ``` data +-- day @@ -44,7 +39,6 @@ config Deleting notes is done by clearing contents and clicking "Save" - the app deletes empty files when saving. ### Config options: - Below are the available configuration options and their defaults. The settings are defined as newline separated `key=value` pairs in the config file. If you do not provide an option, the default will be used. @@ -71,14 +65,12 @@ tg_topic=message_thread_id ``` ### Docker deployment: - The Docker images are hosted via GitHub over at `ghcr.io/andrew-71/hibiscus:`, built from the [Dockerfile](./Dockerfile). This repo contains the [compose.yml](./compose.yml) that I personally use. *Note: an extremely outdated self-hosted [package](https://git.a71.su/Andrew71/hibiscus/packages) will be provided for some time.* ### Executable flags - If you decide to use plain executable instead of docker, it supports the following flags: ``` -config string @@ -94,7 +86,6 @@ If you decide to use plain executable instead of docker, it supports the followi ``` ### API methods - You can access the API at `/api/`. It is protected by same HTTP Basic Auth as "normal" routes. ``` GET /today - get file contents for today diff --git a/TODO.md b/TODO.md index f5303b4..de2299c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,15 +1,8 @@ # TODO List of things to add to this project -## Urgent (1.1.5-2.0.0) -* `style.css` in config instead of theme (provide themes as examples in repo) -* man page, maybe try packaging for fun * Auth improvement so it DOESN'T ASK ME FOR PASSWORD EVERY DAY UGH XD - -## Nice to have * Forward/backward buttons for days -* Changelog included -* Refactor code ## Brainstorming Don't expect any of this, these are ideas floating inside my head @@ -24,4 +17,4 @@ Don't expect any of this, these are ideas floating inside my head Is this even a feature that fits the vision? * Better, *multi-page* docs in case others want to use this for some reason * Check export function for improvements -* *Go* dependency-less? <-- this is a terrible idea \ No newline at end of file +* *Go* dependency-less? <-- this is a terrible idea diff --git a/auth.go b/auth.go index 0f2aee7..cc255e2 100644 --- a/auth.go +++ b/auth.go @@ -27,7 +27,7 @@ func NoteLoginFail(username string, password string, r *http.Request) { attempt := failedLogin{username, password, time.Now()} updatedLogins := []failedLogin{attempt} for _, attempt := range failedLogins { - if 100 > time.Since(attempt.Timestamp).Seconds() { + if 100 > time.Now().Sub(attempt.Timestamp).Abs().Seconds() { updatedLogins = append(updatedLogins, attempt) } } diff --git a/config.go b/config.go index 0426092..6316dee 100644 --- a/config.go +++ b/config.go @@ -120,7 +120,13 @@ func (c *Config) Reload() error { } } case "bool": - fieldElem.SetBool(v == "true") + { + if v == "true" { + fieldElem.SetBool(true) + } else { + fieldElem.SetBool(false) + } + } case "location": timezone = v case "duration": @@ -173,7 +179,7 @@ func ConfigReloadApi(w http.ResponseWriter, r *http.Request) { HandleWrite(w.Write([]byte(err.Error()))) } if r.Referer() != "" { - http.Redirect(w, r, r.Header.Get("Referer"), http.StatusFound) + http.Redirect(w, r, r.Header.Get("Referer"), 302) return } w.WriteHeader(http.StatusOK) diff --git a/go.mod b/go.mod index d798fb8..c39d590 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module hibiscus-txt +module hibiscus go 1.22 diff --git a/i18n/en.json b/i18n/en.json index c6fac67..6ce3567 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -27,9 +27,5 @@ "info.config": "Edit config", "info.telegram.auth_fail": "Failed auth attempt in Hibiscus.txt", - "info.telegram.scram": "Hibiscus SCRAM triggered, shutting down", - - "error.404": "The page you were looking for doesn't exist", - "error.500": "It's probably not your fault, but something broke", - "error.prompt": "Go home?" + "info.telegram.scram": "Hibiscus SCRAM triggered, shutting down" } \ No newline at end of file diff --git a/i18n/ru.json b/i18n/ru.json index 3ac0302..ac34428 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -27,9 +27,5 @@ "info.config": "Редактировать конфиг", "info.telegram_notification": "Неверная попытка авторизации в Hibiscus.txt", - "info.telegram.scram": "Активирована функция SCRAM в Hibiscus.txt, сервер выключается", - - "error.404": "Страница, которую вы ищете, не существует", - "error.500": "Что-то сломалось", - "error.prompt": "На главную?" + "info.telegram.scram": "Активирована функция SCRAM в Hibiscus.txt, сервер выключается" } \ No newline at end of file diff --git a/pages/error/404.html b/pages/error/404.html index 48af44e..bbde5d1 100644 --- a/pages/error/404.html +++ b/pages/error/404.html @@ -1,4 +1,3 @@ -{{- define "404" -}} @@ -11,9 +10,8 @@

Error 404 - Not Found

-

{{ translatableText "error.404" }}

-

{{ translatableText "error.prompt" }}

+

The page you were looking for doesn't exist or was moved

+

Go home?

- -{{ end }} \ No newline at end of file + \ No newline at end of file diff --git a/pages/error/500.html b/pages/error/500.html index 4da0874..a58daf5 100644 --- a/pages/error/500.html +++ b/pages/error/500.html @@ -1,4 +1,3 @@ -{{- define "500" -}} @@ -11,9 +10,8 @@

Error 500 - Internal Server Error

-

{{ translatableText "error.500" }}

-

{{ translatableText "error.prompt" }}

+

It's probably not your fault, but something broke

+

Go home?

- -{{ end }} \ No newline at end of file + \ No newline at end of file diff --git a/public/main.css b/public/main.css index 993eb06..19250a4 100644 --- a/public/main.css +++ b/public/main.css @@ -1,57 +1,49 @@ /* Default theme */ :root { /* Light theme */ - --text-light: #2b2a2a; - --bg-light: #f4edd7; + --text-light: #454545; + --bg-light: #f5f0e1; - --clickable-light: #ed3e3b; - --clickable-hover-light: #e55552; - --clickable-label-light: #f4edd7; + --clickable-light: #f85552; + --clickable-hover-light: #e66868; + --clickable-label-light: #f5f2ee; --text-hover-light: #656565; - --textarea-bg-light: #f9f5e4; - --textarea-border-light: #c3c3c2; + --textarea-bg-light: #f5f2ee; + --textarea-border-light: #454545; /* Dark theme */ --text-dark: #f5f0e1; - --bg-dark: #1b1916; + --bg-dark: #2c2825; - --clickable-dark: #ed3e3b; - --clickable-hover-dark: #ae3836; + --clickable-dark: #f85552; + --clickable-hover-dark: #e66868; --clickable-label-dark: #f5f2ee; - --text-hover-dark: #a9a8a4; + --text-hover-dark: #656565; - --textarea-bg-dark: #201d1b; /* 252020 f5f0e1 */ - --textarea-border-dark: #2c2727; + --textarea-bg-dark: #383030; + --textarea-border-dark: #454545; } * { box-sizing: border-box; } body { color: var(--text-light); background-color: var(--bg-light); - font-size: 18px; margin: auto auto; max-width: 640px; - padding: 15px; + padding: 1em; line-height: 1.4; font-family: serif; min-height: 85vh; display: flex; flex-direction: column; } -h1,h2,h3,h4,h5,h6 { line-height: 1.2 } - a, a:visited { color: var(--clickable-light); } a:hover, a:visited:hover { color: var(--clickable-hover-light); } a.no-accent, a.no-accent:visited { color: var(--text-light); } a.no-accent:hover, a.no-accent:visited:hover { color: var(--text-hover-light); } -ul:not(li ul), ol:not(li ol){ - margin-left: 0; - padding-left: 0; - list-style-position: inside; -} - +h2 { margin-bottom:12px; } .list-title { margin-bottom: 0} .list-desc { margin-top: 0 } @@ -63,7 +55,7 @@ textarea, input { resize: vertical; outline: 0; box-shadow: none; - border: 2px solid var(--textarea-border-light); + border: 0.0625em solid var(--textarea-border-light); margin-bottom: 1em; font-size: 18px; } diff --git a/routes.go b/routes.go index 4386e57..d2ff112 100644 --- a/routes.go +++ b/routes.go @@ -55,30 +55,16 @@ var editTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(P var viewTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(Pages, "pages/base.html", "pages/entry.html")) var listTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(Pages, "pages/base.html", "pages/list.html")) -var template404 = template.Must(template.New("404").Funcs(templateFuncs).ParseFS(Pages, "pages/error/404.html")) // NotFound returns a user-friendly 404 error page. func NotFound(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) - - err := template404.Execute(w, nil) - if err != nil { - slog.Error("error rendering error 404 page", "error", err) - InternalError(w, r) - return - } + HandleWrite(w.Write(EmbeddedPage("pages/error/404.html"))) } -var template500 = template.Must(template.New("500").Funcs(templateFuncs).ParseFS(Pages, "pages/error/500.html")) // InternalError returns a user-friendly 500 error page. func InternalError(w http.ResponseWriter, r *http.Request) { w.WriteHeader(500) - - err := template500.Execute(w, nil) - if err != nil { // Well this is awkward - slog.Error("error rendering error 500 page", "error", err) - HandleWrite(w.Write([]byte("500. Something went *very* wrong."))) - return - } + HandleWrite(w.Write(EmbeddedPage("pages/error/500.html"))) } // GetEntries handles showing a list. @@ -176,7 +162,7 @@ func PostEntry(filename string, w http.ResponseWriter, r *http.Request) { slog.Error("error saving file", "error", err, "file", filename) } if r.Referer() != "" { - http.Redirect(w, r, r.Header.Get("Referer"), http.StatusFound) + http.Redirect(w, r, r.Header.Get("Referer"), 302) return } } @@ -190,7 +176,7 @@ func GetDay(w http.ResponseWriter, r *http.Request) { return } if dayString == TodayDate() { // Today can still be edited - http.Redirect(w, r, "/", http.StatusFound) + http.Redirect(w, r, "/", 302) return }