1
0

Current state of porting to a Templ template engine. Stage 2.

This commit is contained in:
Alexander Andreev 2024-06-19 01:08:05 +04:00
parent 77aa7a5e63
commit 89de89671a
Signed by: Arav
GPG Key ID: 25969B23DCB5CA34
15 changed files with 543 additions and 249 deletions

View File

@ -37,31 +37,29 @@ func NewHandlers(captchaExpire time.Duration, owner string, gbPageSize int64,
} }
func (h *Handlers) Privacy(w http.ResponseWriter, r *http.Request) { func (h *Handlers) Privacy(w http.ResponseWriter, r *http.Request) {
web.Privacy(r).Render(context.Background(), w)
web.Privacy("/ Privacy statements",
util.GetServiceByHost(r.Host, util.ServiceRadio),
util.GetServiceByHost(r.Host, util.ServiceRadio),
util.GetServiceByHost(r.Host, util.ServiceUpload), w)
} }
func (h *Handlers) Stuff(w http.ResponseWriter, r *http.Request) { func (h *Handlers) Stuff(w http.ResponseWriter, r *http.Request) {
web.Stuff("/ Stuff", util.GetServiceByHost(r.Host, util.ServiceGit), web.Stuff(r).Render(context.Background(), w)
util.GetServiceByHost(r.Host, util.ServiceFiles), web.Metadata, w)
} }
func (h *Handlers) Mindflow(w http.ResponseWriter, r *http.Request) { func (h *Handlers) Mindflow(w http.ResponseWriter, r *http.Request) {
posts, err := h.mindflowDB.Posts() posts, err := h.mindflowDB.Posts()
if err != nil { if err != nil {
log.Println("Cannot load posts.", err)
Error(w, http.StatusInternalServerError, "Cannot load posts.", "", r.Referer())
return return
} }
categories, err := h.mindflowDB.Categories() categories, err := h.mindflowDB.Categories()
if err != nil { if err != nil {
log.Println(err) log.Println("Cannot load categories.", err)
Error(w, http.StatusInternalServerError, "Cannot load categories.", "", r.Referer())
return return
} }
web.Mindflow("/ Mindflow", posts, categories, r, w) web.Mindflow(posts, categories, r).Render(context.Background(), w)
} }
func (h *Handlers) MindflowAdmin(w http.ResponseWriter, r *http.Request) { func (h *Handlers) MindflowAdmin(w http.ResponseWriter, r *http.Request) {
@ -77,7 +75,7 @@ func (h *Handlers) MindflowAdmin(w http.ResponseWriter, r *http.Request) {
return return
} }
web.MindflowAdmin("/ Mindflow Administration", posts, categories, r, w) web.MindflowAdmin(posts, categories, r).Render(context.Background(), w)
} }
func (h *Handlers) About(w http.ResponseWriter, r *http.Request) { func (h *Handlers) About(w http.ResponseWriter, r *http.Request) {
@ -95,18 +93,18 @@ func (h *Handlers) About(w http.ResponseWriter, r *http.Request) {
} }
} }
web.About("/ About", util.GetServiceByHost(r.Host, util.ServiceFiles), lst, w) web.About(util.GetServiceByHost(r.Host, util.ServiceFiles), lst).Render(context.Background(), w)
} }
func (h *Handlers) Article(w http.ResponseWriter, r *http.Request) { func (h *Handlers) Article(w http.ResponseWriter, r *http.Request) {
name := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:] name := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:]
artcl := web.GetArticle(name) artcl := web.GetArticle(name)
if artcl == nil { if artcl == nil {
http.Error(w, "an article doesn't exist", http.StatusNotFound) Error(w, http.StatusNotFound, "", "An article \""+name+"\" doesn't exist.", r.Referer())
return return
} }
web.Article(artcl.Title, artcl.Description, string(artcl.Body), artcl.Date, r.Host, name, r, w) web.Article(artcl.Title, artcl.Description, string(artcl.Body), name, artcl.Date, r).Render(context.Background(), w)
} }
func (h *Handlers) Guestbook(w http.ResponseWriter, r *http.Request) { func (h *Handlers) Guestbook(w http.ResponseWriter, r *http.Request) {
@ -157,7 +155,7 @@ func (h *Handlers) GuestbookAdmin(w http.ResponseWriter, r *http.Request) {
entry.Message = strings.ReplaceAll(entry.Message, "\\n", "\n") entry.Message = strings.ReplaceAll(entry.Message, "\\n", "\n")
} }
web.GuestbookAdmin("/ Guestbook Administration", h.owner, entries, r, w) web.GuestbookAdmin(h.owner, entries, r).Render(context.Background(), w)
} }
func (h *Handlers) RSS(w http.ResponseWriter, r *http.Request) { func (h *Handlers) RSS(w http.ResponseWriter, r *http.Request) {

11
web/about.templ Normal file
View File

@ -0,0 +1,11 @@
package web
import "git.arav.su/Arav/dwelling-home/pkg/servicestat"
templ About(filesSrvc string, services servicestat.ServiceList) {
@base("About", "About me and my home servers.", "about, me, servcies", "/about", "About", aboutHead())
}
templ aboutHead() {
<link rel="stylesheet" href="/assets/css/about.css"/>
}

26
web/article.templ Normal file
View File

@ -0,0 +1,26 @@
package web
import "time"
import "net/http"
import "git.arav.su/Arav/dwelling-home/pkg/util"
templ Article(title, description, body, urlName string, date time.Time, r *http.Request) {
@base(title + " - Articles", description, "", "/stuff/article/"+urlName, "Articles", articleHead()) {
<article>
<header>
<h2>{ title }</h2>
<div class="menu">
<a href="/stuff#articles">Go back to articles list</a>
{{ dctz := util.ToClientTimezone(date, r) }}
<time datetime={ dctz.Format("2006-01-02") }>{ dctz.Format("02 January 2006") }</time>
</div>
</header>
@templ.Raw(body)
</article>
}
}
templ articleHead() {
<link rel="stylesheet" href="/assets/css/articles.css"/>
}

View File

@ -5,3 +5,7 @@
margin: 6rem 0; } margin: 6rem 0; }
#error h1 { font-size: 8rem; } #error h1 { font-size: 8rem; }
#error p {
font-size: 1.1rem;
text-align: center; }

View File

@ -58,6 +58,8 @@ button.refresh:disabled {
text-align: center; text-align: center;
width: 4.5rem; } width: 4.5rem; }
article p { white-space: pre; }
input[type="submit"] { input[type="submit"] {
background-color: var(--primary-color); background-color: var(--primary-color);
border: none; border: none;

View File

@ -1,9 +1,9 @@
package web package web
import "strings" // import "strings"
templ base(title, description, keywords, canonical, heading string, head templ.Component) { templ base(title, description, keywords, canonical, heading string, head templ.Component) {
<!doctype html> <!DOCTYPE html>
<html> <html>
<head> <head>
if title != "" { if title != "" {
@ -20,8 +20,12 @@ templ base(title, description, keywords, canonical, heading string, head templ.C
<link rel="icon" href="/assets/img/favicon.svg" sizes="any" type="image/svg+xml"/> <link rel="icon" href="/assets/img/favicon.svg" sizes="any" type="image/svg+xml"/>
<link rel="stylesheet" href="/assets/css/main.css"/> <link rel="stylesheet" href="/assets/css/main.css"/>
<link rel="alternate" href="/rss.xml" type="application/rss+xml" title="Arav's dwelling"/> <link rel="alternate" href="/rss.xml" type="application/rss+xml" title="Arav's dwelling"/>
if canonical != "" {
<link rel="canonical" href={ string(templ.URL(canonical)) }/> <link rel="canonical" href={ string(templ.URL(canonical)) }/>
}
if head != nil {
@head @head
}
</head> </head>
<body> <body>
<header> <header>
@ -29,14 +33,12 @@ templ base(title, description, keywords, canonical, heading string, head templ.C
<text class="logo">Arav's dwelling</text> <text class="logo">Arav's dwelling</text>
<text class="under" y="11">Welcome to my sacred place, wanderer</text> <text class="under" y="11">Welcome to my sacred place, wanderer</text>
</svg> </svg>
<nav>
@navigation(heading) @navigation(heading)
</nav>
</header> </header>
{ children... } { children... }
<footer> <footer>
<a href="/rss.xml" title="Stay up to date on what's going on.">RSS feed</a> <a href="/rss.xml" title="Stay up to date on what's going on.">RSS feed</a>
<br> <br/>
&copy; 2017&mdash;2024 Alexander &quot;Arav&quot; Andreev &lt;<a href="mailto:me@arav.su">me@arav.su</a>&gt; <a href="/privacy">Privacy statements</a> &copy; 2017&mdash;2024 Alexander &quot;Arav&quot; Andreev &lt;<a href="mailto:me@arav.su">me@arav.su</a>&gt; <a href="/privacy">Privacy statements</a>
</footer> </footer>
</body> </body>
@ -46,14 +48,17 @@ templ base(title, description, keywords, canonical, heading string, head templ.C
var navElements = []string{"Stuff", "Mindflow", "About", "Guestbook"} var navElements = []string{"Stuff", "Mindflow", "About", "Guestbook"}
templ navigation(heading string) { templ navigation(heading string) {
for _, n := range navElements { <nav>
if n == heading { if heading != "Home" {
continue <a href="/">Home</a>
}
<a href={ templ.SafeURL("/" + strings.ToLower(n)) }>{ n }</a>
} }
<a href="/stuff">Stuff</a>
<a href="/mindflow">Mindflow</a>
<a href="/about">About</a>
<a href="/guestbook">Guestbook</a>
if heading != "" { if heading != "" && heading != "Home" {
<h1>{ heading }</h1> <h1>{ heading }</h1>
} }
</nav>
} }

View File

@ -5,8 +5,7 @@ import "net/http"
templ ErrorXXX(errCode int, reason, message, referer string) { templ ErrorXXX(errCode int, reason, message, referer string) {
{{ errText := http.StatusText(errCode) }} {{ errText := http.StatusText(errCode) }}
@base(errText, errText, @base(errText, errText, "", "", errText, errorXXXHead()) {
"", "", errText, nil) {
<section id="error"> <section id="error">
<h1>{ fmt.Sprint(errCode) }</h1> <h1>{ fmt.Sprint(errCode) }</h1>
{ errText } { errText }
@ -24,3 +23,7 @@ templ ErrorXXX(errCode int, reason, message, referer string) {
} }
} }
} }
templ errorXXXHead() {
<link rel="stylesheet" href="/assets/css/error.css">
}

View File

@ -10,9 +10,7 @@ import "git.arav.su/Arav/justguestbook"
import "git.arav.su/Arav/dwelling-home/pkg/util" import "git.arav.su/Arav/dwelling-home/pkg/util"
templ Guestbook(captchaID, owner string, entries []*justguestbook.Entry, pageCount int64, r *http.Request) { templ Guestbook(captchaID, owner string, entries []*justguestbook.Entry, pageCount int64, r *http.Request) {
@base("Guestbook", @base("Guestbook", "This is my guestbook. Welcome.", "guestbook, personal", "/guestbook", "Guestbook", guestbookHead()) {
"This is my guestbook. Welcome.",
"guestbook, personal", "/guestbook", "Guestbook", guestbookHead()) {
<form id="new-post" action="/api/guestbook" method="POST"> <form id="new-post" action="/api/guestbook" method="POST">
<input type="text" name="name" maxlength="80" placeholder="Name (Anonymous if left blank)"/> <input type="text" name="name" maxlength="80" placeholder="Name (Anonymous if left blank)"/>
<input type="text" name="website" maxlength="255" placeholder="Website (optional)"/> <input type="text" name="website" maxlength="255" placeholder="Website (optional)"/>
@ -20,7 +18,7 @@ templ Guestbook(captchaID, owner string, entries []*justguestbook.Entry, pageCou
<span class="checkboxes"> <span class="checkboxes">
<input type="checkbox" name="hide_website" id="hide-website" checked/> <input type="checkbox" name="hide_website" id="hide-website" checked/>
<label for="hide-website">Hide website <small>(only I can see if set)</small></label> <label for="hide-website">Hide website <small>(only I can see if set)</small></label>
<br> <br/>
<small>Use &gt; to make a quote.</small> <small>Use &gt; to make a quote.</small>
</span> </span>
<span class="captcha"> <span class="captcha">
@ -44,9 +42,11 @@ templ Guestbook(captchaID, owner string, entries []*justguestbook.Entry, pageCou
</header> </header>
for _, line := range strings.Split(entry.Message, "\n") { for _, line := range strings.Split(entry.Message, "\n") {
if len(line) > 0 && line[0] == '>' { if len(line) > 0 && line[0] == '>' {
<p class="quote">{ line }</p> <p class="quote">@templ.Raw(line)
</p>
} else { } else {
<p>{ line }</p> <p>@templ.Raw(line)
</p>
} }
} }
if entry.Reply != nil { if entry.Reply != nil {
@ -57,9 +57,11 @@ templ Guestbook(captchaID, owner string, entries []*justguestbook.Entry, pageCou
</header> </header>
for _, line := range strings.Split(entry.Reply.Message, "\n") { for _, line := range strings.Split(entry.Reply.Message, "\n") {
if len(line) > 0 && line[0] == '>' { if len(line) > 0 && line[0] == '>' {
<p class="quote">{ line }</p> <p class="quote">@templ.Raw(line)
</p>
} else { } else {
<p>{ line }</p> <p>@templ.Raw(line)
</p>
} }
} }
</div> </div>

View File

@ -0,0 +1,9 @@
package web
import "net/http"
import "git.arav.su/Arav/justguestbook"
templ GuestbookAdmin(owner string, entries []*justguestbook.Entry, r *http.Request) {
@base("Guestbook Administration", "", "", "/guestbook/admin", "Guestbook Administration", nil)
}

View File

@ -3,59 +3,24 @@ package web
templ Index() { templ Index() {
@base("", @base("",
"A homepage of a russian guy Alexander aka Arav. Not just homepage, but something more...", "/", "A homepage of a russian guy Alexander aka Arav. Not just homepage, but something more...", "/",
"homepage, personal, blog, services, self-hosting", "", nil) { "homepage, personal, blog, services, self-hosting", "Home", indexHead()) {
<section id="services"> <section id="services">
<span> <span>
<a href="https://arav.su">arav.su</a> <a href="https://arav.su">arav.su</a>.<a href="http://moq7aejnf4xk5k2bkaltli3ftkhusy2mbrd3pj23nrca343ku2mgk4yd.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::f]">ygg</a>.<a href="http://arav.i2p">i2p</a><sup><a href="http://arav.i2p/?i2paddresshelper=5Kl-DiWbbk6wf7m0v6zBSNHYq3sXlnrWLIWVeGdpPbPyc9CBS~zrzDYpP43rv1fRiIkbVCD5hTEpY6joQGlk-dFkWWD6201qa6ecsDVQMaE3Q7UTYICd0VEBRoqDUSrvsM-P2y5oG4Z-77RmoGKpbcRgNuMVbQ7AGJNqVSGej-lSyscDWTIZT5dCT505lfRwprdD~emZqkwnn22X16Wpj-X4A4ifph4idrThGioz4UW6PrCpa-oebMCo217s0Zyl9VKaU-o9cx5eFUEwnshoUjqwh7VE-S45NDz854J08xldCATM3wwTRVXhc2NUypsJLKFKiV0z3EXN-ApCdxsV60C-eiXUTX5vYcHHH~imA79v8WKFybjnsyUBst5BBEPQIUifTceLUrTmQ9TUpaMV90EsD5SCshmCfOs8R5y2dK6EfQu8iyYAB5VFSH4M1CLiBZUsDTEFiOomn2JGMDnbPho8lMB8ss4SMuwZShb2LlGqLxJ38kRHlvC68VmJO7InBQAEAAcAAA==" title="Address helper">ah</a></sup>
.
<a href="http://moq7aejnf4xk5k2bkaltli3ftkhusy2mbrd3pj23nrca343ku2mgk4yd.onion">onion</a>
.
<a href="http://[300:a98d:d6d0:8a08::f]">ygg</a>
.
<a href="http://arav.i2p">i2p</a>
<sup><a href="http://arav.i2p/?i2paddresshelper=5Kl-DiWbbk6wf7m0v6zBSNHYq3sXlnrWLIWVeGdpPbPyc9CBS~zrzDYpP43rv1fRiIkbVCD5hTEpY6joQGlk-dFkWWD6201qa6ecsDVQMaE3Q7UTYICd0VEBRoqDUSrvsM-P2y5oG4Z-77RmoGKpbcRgNuMVbQ7AGJNqVSGej-lSyscDWTIZT5dCT505lfRwprdD~emZqkwnn22X16Wpj-X4A4ifph4idrThGioz4UW6PrCpa-oebMCo217s0Zyl9VKaU-o9cx5eFUEwnshoUjqwh7VE-S45NDz854J08xldCATM3wwTRVXhc2NUypsJLKFKiV0z3EXN-ApCdxsV60C-eiXUTX5vYcHHH~imA79v8WKFybjnsyUBst5BBEPQIUifTceLUrTmQ9TUpaMV90EsD5SCshmCfOs8R5y2dK6EfQu8iyYAB5VFSH4M1CLiBZUsDTEFiOomn2JGMDnbPho8lMB8ss4SMuwZShb2LlGqLxJ38kRHlvC68VmJO7InBQAEAAcAAA==" title="Address helper">ah</a></sup>
</span> </span>
<a href="https://arav.neocities.org">arav.neocities.org</a> <a href="https://arav.neocities.org">arav.neocities.org</a>
<br> <br/>
<span> <span>
<a href="https://radio.arav.su">radio</a> <a href="https://radio.arav.su">radio</a>.<a href="http://wsmkgnmhmzqm7kyzv7jnzzafvgm7xlmlfvzhgorpapd5or2arnhuktqd.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>.<a href="http://radio.arav.i2p">i2p</a><sup><a href="http://radio.arav.i2p/?i2paddresshelper=NfCKBu9vjLFiBMEPQGiZT9AzGlhkKHzYrKM66FL-ESeDbnYUY--NzukO9UA28s3WThhDQVge2TmyfYsaZiUw~AjuLsykxS13pebs7lkAVY1jm77La-eFFIAQ22Vtd2YgS0vbhRMzuDxKkCR1vPwNax8R2o6a07xsQvvDml6UQxG4p5vt44JA2geQNvQfm8cEiSa6gNJZJSW3rWuLDg6~1Jy3D70oSVSlNfihmG4JtNV6tVBjJE2h5gUxfhYZACttpGTPM~UNF~lrSujlBQsCqdzvLswdMw~FnvpfGzJcJroeFTerRyH6oUkkDSOK7uWwl0e70vKxrIbFgJjKtjlLWlUCI5N0TnJP4Hzt2pttB~R0hSr2vVl8ky0yJEtN3rwnrJkw7q0ZIH30ngTfxsCTbolAzl6liN9Ez5YF97zDOPnVFmvQ6Eg1PyFdypQO1PiUHqF56SWhx3utGwecUS6jJCvsKIJJVEIMVcD6h7S0z1g1rqQ4jbg5UfXPwFEgFOlzBQAEAAcAAA==" title="Address helper">ah</a></sup>
.
<a href="http://wsmkgnmhmzqm7kyzv7jnzzafvgm7xlmlfvzhgorpapd5or2arnhuktqd.onion">onion</a>
.
<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>
.
<a href="http://radio.arav.i2p">i2p</a>
<sup><a href="http://radio.arav.i2p/?i2paddresshelper=NfCKBu9vjLFiBMEPQGiZT9AzGlhkKHzYrKM66FL-ESeDbnYUY--NzukO9UA28s3WThhDQVge2TmyfYsaZiUw~AjuLsykxS13pebs7lkAVY1jm77La-eFFIAQ22Vtd2YgS0vbhRMzuDxKkCR1vPwNax8R2o6a07xsQvvDml6UQxG4p5vt44JA2geQNvQfm8cEiSa6gNJZJSW3rWuLDg6~1Jy3D70oSVSlNfihmG4JtNV6tVBjJE2h5gUxfhYZACttpGTPM~UNF~lrSujlBQsCqdzvLswdMw~FnvpfGzJcJroeFTerRyH6oUkkDSOK7uWwl0e70vKxrIbFgJjKtjlLWlUCI5N0TnJP4Hzt2pttB~R0hSr2vVl8ky0yJEtN3rwnrJkw7q0ZIH30ngTfxsCTbolAzl6liN9Ez5YF97zDOPnVFmvQ6Eg1PyFdypQO1PiUHqF56SWhx3utGwecUS6jJCvsKIJJVEIMVcD6h7S0z1g1rqQ4jbg5UfXPwFEgFOlzBQAEAAcAAA==" title="Address helper">ah</a></sup>
</span> </span>
<span> <span>
<a href="https://files.arav.su">files</a> <a href="https://files.arav.su">files</a>.<a href="http://qf5e43nlhvnrutmikuvbdfj3cmtthokpbaxtkm6mjlslttzvtgm4fxid.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>.<a href="http://files.arav.i2p">i2p</a><sup><a href="http://files.arav.i2p/?i2paddresshelper=48vtYgeVnju7B2FaR0zxUL3MQXN9QjK~Ggya45aANwm86mtpemuEkaskJmEQaFSd4FcDAFIiXHfNpfGqoupLwNmtgBmGRcuVV8xb2W~W6lM0oOhovjB37EUaMWs3AI5aIES84QOqApgwYX-ANIcwa~Kg6AbMuX8D8qnejuhBbuCffYah-TD8e~O0cnyqxzLTmxIGCyk2egdYXwanJyYFDocomIVfcqfJ0MgjIHhFQtkcb0e84bxvDzcAFIpEDrzAo4GVrFn-TCu0Lyf2ccqmVpucFl0UGhuVRxEt19KLd3PxlfwHv2lmzTZtq9CbnfaoPntUPx1sf84QnZDmrXWhVK8p3VvuPZMxjyz9KyhPjrGkO4E0oibDlvKuMsGEm-GkZsKxgXo~CrdcVtN8suAwW6rACAuk8gq2jUMBZBZ12migPZ7miHftEkOFHfgfUiKBwirrw~y9Zi261WX4-EVe2oD4pkhQOrqOKIoI-vv5z9CpQ7PKL531kgkipcBseXybBQAEAAcAAA==" title="Address helper">ah</a></sup>
.
<a href="http://qf5e43nlhvnrutmikuvbdfj3cmtthokpbaxtkm6mjlslttzvtgm4fxid.onion">onion</a>
.
<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>
.
<a href="http://files.arav.i2p">i2p</a>
<sup><a href="http://files.arav.i2p/?i2paddresshelper=48vtYgeVnju7B2FaR0zxUL3MQXN9QjK~Ggya45aANwm86mtpemuEkaskJmEQaFSd4FcDAFIiXHfNpfGqoupLwNmtgBmGRcuVV8xb2W~W6lM0oOhovjB37EUaMWs3AI5aIES84QOqApgwYX-ANIcwa~Kg6AbMuX8D8qnejuhBbuCffYah-TD8e~O0cnyqxzLTmxIGCyk2egdYXwanJyYFDocomIVfcqfJ0MgjIHhFQtkcb0e84bxvDzcAFIpEDrzAo4GVrFn-TCu0Lyf2ccqmVpucFl0UGhuVRxEt19KLd3PxlfwHv2lmzTZtq9CbnfaoPntUPx1sf84QnZDmrXWhVK8p3VvuPZMxjyz9KyhPjrGkO4E0oibDlvKuMsGEm-GkZsKxgXo~CrdcVtN8suAwW6rACAuk8gq2jUMBZBZ12migPZ7miHftEkOFHfgfUiKBwirrw~y9Zi261WX4-EVe2oD4pkhQOrqOKIoI-vv5z9CpQ7PKL531kgkipcBseXybBQAEAAcAAA==" title="Address helper">ah</a></sup>
</span> </span>
<span> <span>
<a href="https://upload.arav.su">upload</a> <a href="https://upload.arav.su">upload</a>.<a href="http://4usftbmjpfexkr2x5xbp5ukmygpmg4fgrnx2wbifsexqctooz5hmviyd.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>.<a href="http://upload.arav.i2p">i2p</a><sup><a href="http://upload.arav.i2p/?i2paddresshelper=b5NWA2vNydWSv6~8KN4e~td2UVGkYsayKPa1PnXI87A3gsg6m978tIehHLVN4XcCfUq4aB-59hqqZicorRnHKfV3lVdx9mdhC8Bhj~bMAcwMgWoXidqZNrWMoFGzWotFsa3nWh4zsRUSfrokecC8u9Y06byfSS1siyak0J6xpsggXRqqgNF0-8ncPeqvzBxHB9NRDXWEVJGS9HSpydWl1UpjgZffcd~NZroxkSAfughHcFAn2OLKkaZRe6WqCJQfJoXTCyz4wkFmYbH1CSddWlddmWaaU7icsbQrZm3XEqKTVKvm86G6ehxmzyHqCumc4GOWswcP0E51UQVOv-WA8R6SWQAj6ZnZhnCoCNFFEfW2lBiDmTnLJbfm-C-AdI6G1~dQ1~3FCH6wXWy-2DebpyoVVt9epzU7l4l2MVeaOUahbf6wcol1UbxPoR0XlGCXDe9700TYePjtpOU9vNkk2B1dQiZ1usgwseYuO26cRogSvbi8poz4BlCNO733HR1XBQAEAAcAAA==" title="Address helper">ah</a></sup>
.
<a href="http://4usftbmjpfexkr2x5xbp5ukmygpmg4fgrnx2wbifsexqctooz5hmviyd.onion">onion</a>
.
<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>
.
<a href="http://upload.arav.i2p">i2p</a>
<sup><a href="http://upload.arav.i2p/?i2paddresshelper=b5NWA2vNydWSv6~8KN4e~td2UVGkYsayKPa1PnXI87A3gsg6m978tIehHLVN4XcCfUq4aB-59hqqZicorRnHKfV3lVdx9mdhC8Bhj~bMAcwMgWoXidqZNrWMoFGzWotFsa3nWh4zsRUSfrokecC8u9Y06byfSS1siyak0J6xpsggXRqqgNF0-8ncPeqvzBxHB9NRDXWEVJGS9HSpydWl1UpjgZffcd~NZroxkSAfughHcFAn2OLKkaZRe6WqCJQfJoXTCyz4wkFmYbH1CSddWlddmWaaU7icsbQrZm3XEqKTVKvm86G6ehxmzyHqCumc4GOWswcP0E51UQVOv-WA8R6SWQAj6ZnZhnCoCNFFEfW2lBiDmTnLJbfm-C-AdI6G1~dQ1~3FCH6wXWy-2DebpyoVVt9epzU7l4l2MVeaOUahbf6wcol1UbxPoR0XlGCXDe9700TYePjtpOU9vNkk2B1dQiZ1usgwseYuO26cRogSvbi8poz4BlCNO733HR1XBQAEAAcAAA==" title="Address helper">ah</a></sup>
</span> </span>
<span> <span>
<a href="https://git.arav.su">git</a> <a href="https://git.arav.su">git</a>.<a href="http://qqitm7qlsbbubwmjos4cqzmvkqidg34rfnbyhuydhalep33fbvh22xyd.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>.<a href="http://git.arav.i2p">i2p</a><sup><a href="http://git.arav.i2p/?i2paddresshelper=eFIfcBUv3lHFSnglHfncs5XXtYwm9gCpmAYuio~9CeENBAXKRggPiY1tQC-otCon2hCSpr56WlVBeZk1txKuUnbjHTN7GBFaKW5wJEO2WmKEWPKdcjUDOYZN0D3TwXaYfiBuELD3200lBfDmPEJ01iC2o7B5yvpOqtEKDcaqkIp4vafDuPPumJ~XiCGdUAe~vr52w3Tbuz5x7wbltk-gUELY0-ZAQBos4jOJ6QT1W1lhycHPhAK8qslgwfk94opyIl2pkRyuJhU-2VHc6Fsd621VXC86YAMT1SIfTZlFpoGVCFXDM~BXaLvygFaKf62qardAe0T48Ax6GxosAKXe-yLCVRaiD3KErULfwZXl23kQzRfxM4odG4DWeXawtuvypOmTjHT1skQHU0h52ujye5nT~2bOy14HkCoCnxJ7gSj3MjkmWLd1JhBsPH4ymRmI7jFJR1GYl8Wp5IigMBBzWfJUEEjS7QDHaRo5TCZJ9SXz6sgkGdfh74~r8FWL559gBQAEAAcAAA==" title="Address helper">ah</a></sup>
.
<a href="http://qqitm7qlsbbubwmjos4cqzmvkqidg34rfnbyhuydhalep33fbvh22xyd.onion">onion</a>
.
<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>
.
<a href="http://git.arav.i2p">i2p</a>
<sup><a href="http://git.arav.i2p/?i2paddresshelper=eFIfcBUv3lHFSnglHfncs5XXtYwm9gCpmAYuio~9CeENBAXKRggPiY1tQC-otCon2hCSpr56WlVBeZk1txKuUnbjHTN7GBFaKW5wJEO2WmKEWPKdcjUDOYZN0D3TwXaYfiBuELD3200lBfDmPEJ01iC2o7B5yvpOqtEKDcaqkIp4vafDuPPumJ~XiCGdUAe~vr52w3Tbuz5x7wbltk-gUELY0-ZAQBos4jOJ6QT1W1lhycHPhAK8qslgwfk94opyIl2pkRyuJhU-2VHc6Fsd621VXC86YAMT1SIfTZlFpoGVCFXDM~BXaLvygFaKf62qardAe0T48Ax6GxosAKXe-yLCVRaiD3KErULfwZXl23kQzRfxM4odG4DWeXawtuvypOmTjHT1skQHU0h52ujye5nT~2bOy14HkCoCnxJ7gSj3MjkmWLd1JhBsPH4ymRmI7jFJR1GYl8Wp5IigMBBzWfJUEEjS7QDHaRo5TCZJ9SXz6sgkGdfh74~r8FWL559gBQAEAAcAAA==" title="Address helper">ah</a></sup>
</span> </span>
</section> </section>
<section> <section>
@ -65,3 +30,7 @@ templ Index() {
</section> </section>
} }
} }
templ indexHead() {
<link rel="stylesheet" href="assets/css/index.css"/>
}

56
web/mindflow.templ Normal file
View File

@ -0,0 +1,56 @@
package web
import "net/http"
import "strings"
import "time"
import "git.arav.su/Arav/dwelling-home/pkg/mindflow"
import "git.arav.su/Arav/dwelling-home/pkg/util"
templ Mindflow(posts []mindflow.Post, categories []mindflow.Category, r *http.Request) {
@base("Mindflow", "Updates on my infrastructure, my very important opinions and thoughts.", "updates, thoughts, opinions, blog, diary", "/mindflow", "Mindflow", mindflowHead()) {
<p class="center">Here I post updates on websites and infrastructure, my very important opinions and thoughts no one asked for. If you'd like to subscribe to this bullshittery then <a href="/rss.xml">RSS feed</a> at your service. :)</p>
<section id="filter" class="hidden">
<p class="center">
<button name="all">All</button>
for _, category := range categories {
<button name={ strings.ToLower(category.Name) }>{ category.Name }</button>
}
</p>
</section>
<section>
for _, post := range posts {
<article id={ post.PostID() }>
<header>
<a href={ templ.SafeURL("#" + post.PostID()) }>
<h3>{ post.Category.Name }: { post.Title }</h3>
</a>
</header>
for _, line := range strings.Split(post.Body, "\n") {
if len(line) > 0 && line[0] == '>' {
<p class="quote">{ line }</p>
} else {
<p>{ line }</p>
}
}
<footer>
if post.URL != "" {
<a href={ templ.SafeURL(post.PostURL(r.Host, false)) }>{ post.PostURL(r.Host, false) }</a>
} else {
<span></span>
}
<time datetime={ util.ToClientTimezone(post.Date, r).Format(time.RFC1123) }>{ util.ToClientTimezone(post.Date, r).Format(time.RFC1123) }</time>
</footer>
</article>
}
if len(posts) == 0 {
<p class="center">Nothing? There must be some... Looks like database went down.</p>
}
</section>
}
}
templ mindflowHead() {
<link rel="stylesheet" href="/assets/css/mindflow.css"/>
<script src="/assets/js/mindflow.js" defer></script>
}

9
web/mindflow_admin.templ Normal file
View File

@ -0,0 +1,9 @@
package web
import "net/http"
import "git.arav.su/Arav/dwelling-home/pkg/mindflow"
templ MindflowAdmin(posts []mindflow.Post, categories []mindflow.Category, r *http.Request) {
@base("Mindflow Administration", "", "", "/mindflow/admin", "Mindflow Administration", nil)
}

29
web/privacy.templ Normal file
View File

@ -0,0 +1,29 @@
package web
import "net/http"
import "git.arav.su/Arav/dwelling-home/pkg/util"
templ Privacy(r *http.Request) {
@base("Privacy", "Privacy statements for all of my services.", "privacy statements", "/privacy", "Privacy", nil) {
<section id="privacy">
<h2>Privacy statements</h2>
<h3>General data</h3>
<p>Across all of my Web-services following data is being collected: date of access, IP-address, User-Agent, referer URL, request URL.</p>
<h3>Use of JavaScript</h3>
<p>JS is used on a <a href="/">main website</a> at a guestbook page to refresh CAPTCHA; at mindflow page to filter posts by categories.</p>
<p><a href={ templ.URL(util.GetServiceByHost(r.Host, util.ServiceRadio)) }>Radio service</a> uses JS to update Last N songs list section, and to get current radio statistics.</p>
<p><a href={ templ.URL(util.GetServiceByHost(r.Host, util.ServiceFiles)) }>Files service</a> uses JS to add functionality such as an overlay to view files without the need to leave a site, and implements some keyboard control for convenience.</p>
<h3>Upload service specific</h3>
<p>Every action (upload, download, and delete) is being logged and includes this additional data:</p>
<ol>
<li>File's name it was uploaded/downloaded with;</li>
<li>Unsalted SHA-256 hash of a file;</li>
<li>A salted hash encoded as base64 in raw URL variant that is used to download/delete a file;</li>
<li>File's size.</li>
</ol>
<p>And I will cooperate with law enforcements and provide them with all information (logs and a file itself if it is still present).</p>
<p>As already stated at <a href={ templ.URL(util.GetServiceByHost(r.Host, util.ServiceUpload)) }>Upload service</a>'s page, file's content must comply with law of Russian Federation. Anything like extremist materials, CP, and so on is forbidden.</p>
</section>
}
}

View File

@ -1,8 +1,8 @@
package web package web
import "time"
import "strings"
import "net/http" import "net/http"
import "strings"
import "time"
import "git.arav.su/Arav/dwelling-home/pkg/mindflow" import "git.arav.su/Arav/dwelling-home/pkg/mindflow"
import "git.arav.su/Arav/dwelling-home/pkg/util" import "git.arav.su/Arav/dwelling-home/pkg/util"
@ -15,7 +15,6 @@ templ RSS(host, author string, posts []mindflow.Post, r *http.Request) {
<description>What's going on with me and my machines.</description> <description>What's going on with me and my machines.</description>
<language>en-gb</language> <language>en-gb</language>
<link>{ host }</link> <link>{ host }</link>
for _, post := range posts { for _, post := range posts {
<item> <item>
<title>{ post.Title }</title> <title>{ post.Title }</title>

172
web/stuff.templ Normal file
View File

@ -0,0 +1,172 @@
package web
import "net/http"
import "git.arav.su/Arav/dwelling-home/pkg/util"
templ Stuff(r *http.Request) {
{{ gitSite := util.GetServiceByHost(r.Host, util.ServiceGit) }}
@base("Stuff", "Here I share my programs, scripts, articles, may be other stuff.", "articles, programs, personal projects, own music", "/stuff", "Stuff", nil) {
<p class="center">Here lies everything I've made that I'm willing to share.</p>
<section id="articles">
<h2>Articles</h2>
<table>
<tr>
<th>Last Update</th>
<th>Article</th>
</tr>
for _, entry := range Metadata {
<tr>
<td>
<time datetime={ entry.Date.Format("2006-01-02") }>{ entry.Date.Format("02 January 2006") }</time>
</td>
<td>
<a href={ templ.URL(entry.URL) }>{ entry.Title }</a>
</td>
</tr>
}
</table>
</section>
<section id="programs-scripts">
<h2>Programs and scripts</h2>
<table>
<tr>
<td><b>mccl</b></td>
<td>0.1.2 (14 December 2023)</td>
<td>Go</td>
<td>GPLv3</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/mccl") }>source</a>
<a href={ templ.URL(gitSite + "/Arav/mccl/releases") }>releases</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>A console Minecraft launcher. Take a look at README.md for explanation.</p>
</td>
</tr>
<tr>
<td><b>httpr</b></td>
<td>0.3.2 (20 September 2023)</td>
<td>Go</td>
<td>MIT</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/httpr") }>source</a>
<a href={ templ.URL(gitSite + "/Arav/httpr/releases") }>releases</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>A simple HTTP router that supports having both regular and parametrised path's parts at the same level, like <code>/assets/*filepath</code> and <code>/:a/:b</code> with the same HTTP method.</p>
<p>Yeah, not as efficient as httprouter is, but in my case no performance loose was noticed (on a small amount of paths). Yet I gained prettiness because it allowed me, for example, to ditch <code>/f/</code> part and leave just <code>/:hash/:name</code> instead of <code>/f/:hash/:name</code> in a dwelling-upload service.</p>
</td>
</tr>
<tr>
<td><b>justguestbook</b></td>
<td>1.3.2 (22 May 2023)</td>
<td>Go</td>
<td>MIT</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/justguestbook") }>source</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>A simple guestbook with owner's replies implementation made into a library.</p>
</td>
</tr>
<tr>
<td><b>justcaptcha</b></td>
<td>2.1.0 (12 August 2023)</td>
<td>Go</td>
<td>MIT</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/justcaptcha") }>source</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>A simple CAPTCHA implementation.</p>
</td>
</tr>
<tr>
<td><b>kwh-cost</b></td>
<td>1.1.3 (21 May 2024)</td>
<td>C</td>
<td>MIT+NIGGER</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/kwh-cost") }>source</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>KWh cost calculator in C.</p>
</td>
</tr>
<tr>
<td><b>httpprocprobed</b></td>
<td>3.1.1 (13 January 2024)</td>
<td>Go</td>
<td>MIT+NIGGER</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/httpprocprobed") }>source</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>It returns a list of processes and if they are running in a JSON format via HTTP GET request on <code>/processes</code> endpoint. Under the hood it searches in a /proc/ directory. It is being used on about page to show wether service's running or not.</p>
</td>
</tr>
<tr>
<td><b>ScrapTheChan</b></td>
<td>0.5.0 (3 May 2021)</td>
<td>Python</td>
<td>MIT</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/ScrapTheChan") }>source</a>
<a href={ templ.URL(gitSite + "/Arav/ScrapTheChan/releases") }>releases</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>Imageboards file scraper using theirs JSON API. Currently supported: 4chan.org, lainchan.org, 2ch.hk and 8kun.top.</p>
</td>
</tr>
<tr>
<td><b>OpenNIC active domains extraction script</b></td>
<td>10 July 2020</td>
<td>Bash</td>
<td>MIT</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/opennic-extract-domains") }>source</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>Bash script for BIND9 that extracts domains from zone files of OpenNIC and forms a list of domains that have an IP-address.</p>
</td>
</tr>
<tr>
<td><b>PiggyBank</b></td>
<td>1.0.0 (8 July 2020)</td>
<td>Python</td>
<td>MIT</td>
<td>
<a href={ templ.URL(gitSite + "/Arav/PiggyBank") }>source</a>
<a href={ templ.URL(gitSite + "/Arav/PiggyBank/releases") }>releases</a>
</td>
</tr>
<tr>
<td colspan="5">
<p>A program to help you to keep track of your piggy bank. A simple script I once wrote that I rewrote and made into a package just to learn how to do it.</p>
</td>
</tr>
</table>
</section>
<section id="music">
<h2>Music</h2>
<p>There was a period in my life when I was playing with audio sequencers. I lost all project files and only 3 tracks survived in mp3 and they <a href={ templ.URL(util.GetServiceByHost(r.Host, util.ServiceFiles) + "/music/My%20tracks,%20that%20survived/") }>can be found here</a>.</p>
</section>
}
}