Compare commits

..

40 Commits

Author SHA1 Message Date
c38fd7f435 Merge pull request 'staging' (#10) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 2m21s
Reviewed-on: #10
2025-05-11 16:15:26 +00:00
7ef6b551ac Bugfix Einlesen der Artikel vor Erstellen der Ressourcen
All checks were successful
release-tag / release-image (push) Successful in 2m24s
2025-05-11 17:10:56 +02:00
dce90ca88b bugfix
All checks were successful
release-tag / release-image (push) Successful in 2m20s
2025-05-11 16:56:08 +02:00
7493ca278e fix
All checks were successful
release-tag / release-image (push) Successful in 2m21s
2025-05-11 16:39:14 +02:00
445db0ec10 fix
All checks were successful
release-tag / release-image (push) Successful in 2m21s
2025-05-11 16:29:16 +02:00
87493fe40c removeall fix
All checks were successful
release-tag / release-image (push) Successful in 2m17s
2025-05-11 16:22:48 +02:00
ca22dd8596 Test für Git AutoClone
All checks were successful
release-tag / release-image (push) Successful in 2m14s
2025-05-11 16:16:52 +02:00
e4d47b46e4 Merge pull request 'staging' (#9) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 2m11s
Reviewed-on: #9
2025-05-11 10:18:49 +00:00
4c41bb8838 Anpassung Datenschutzerklärung + ReleaseCandidate
All checks were successful
release-tag / release-image (push) Successful in 2m8s
2025-05-11 12:02:29 +02:00
98de9b1b98 Potentieller Persistenz-Fix
All checks were successful
release-tag / release-image (push) Successful in 2m10s
2025-05-11 11:49:10 +02:00
621db424f0 Fix für Boot-Loop
All checks were successful
release-tag / release-image (push) Successful in 2m12s
2025-05-11 11:34:48 +02:00
7e21b10a6c Persistenz implementiert + Anpassungen
All checks were successful
release-tag / release-image (push) Successful in 2m7s
2025-05-11 11:30:52 +02:00
8cd66c9f59 Anpassungen Counter-Design
All checks were successful
release-tag / release-image (push) Successful in 2m5s
2025-05-11 11:17:45 +02:00
96894516a7 Fix
All checks were successful
release-tag / release-image (push) Successful in 2m9s
2025-05-11 11:11:50 +02:00
2e31bfdc77 Card-Fix für Counter und Berechnungs-Fix
All checks were successful
release-tag / release-image (push) Successful in 2m8s
2025-05-11 11:07:25 +02:00
08ef9c7132 Implementierung eines anonymen Counters - Nicht persistent
All checks were successful
release-tag / release-image (push) Successful in 2m9s
2025-05-11 10:57:36 +02:00
847d860144 Patch
All checks were successful
release-tag / release-image (push) Successful in 2m8s
2025-05-10 22:26:03 +02:00
8b7f1127f8 Fix
All checks were successful
release-tag / release-image (push) Successful in 2m14s
2025-05-10 22:19:11 +02:00
278d3aa48f Invictus 2955 - Das Jahr der Idris-P?
All checks were successful
release-tag / release-image (push) Successful in 2m11s
2025-05-10 22:10:09 +02:00
9dca6a57df Bugfix
All checks were successful
release-tag / release-image (push) Successful in 2m11s
2025-05-10 19:17:30 +02:00
16b5ddfb7b Merge pull request 'Anpassung für dynamische Content-Gits' (#8) from staging into main
Some checks failed
release-tag / release-image (push) Failing after 45s
Reviewed-on: #8
2025-05-10 17:14:28 +00:00
12ce629b31 Anpassung für dynamische Content-Gits
Some checks failed
release-tag / release-image (push) Failing after 43s
2025-05-10 19:13:29 +02:00
5f089d727e Merge pull request 'staging' (#7) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 1m52s
Reviewed-on: #7
2025-05-10 13:09:28 +00:00
d7726b57e4 Windows Server 2025 Domänen-Controller legt Netzwerkprofil auf Öffentlich fest
All checks were successful
release-tag / release-image (push) Successful in 1m51s
2025-05-10 14:54:13 +02:00
c25c60ab27 README.md aktualisiert
All checks were successful
release-tag / release-image (push) Successful in 1m51s
2025-05-08 06:33:34 +00:00
7ee0c9e9f7 TLS-Zertifikat mit SHA3 auf Windows Server 2016 einspielen
All checks were successful
release-tag / release-image (push) Successful in 1m54s
2025-05-08 06:45:56 +02:00
0d98bd064e Merge pull request 'staging' (#6) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 1m49s
Reviewed-on: #6
2025-05-07 20:28:52 +00:00
aba08de902 Source-Patch
All checks were successful
release-tag / release-image (push) Successful in 1m51s
2025-05-07 22:28:23 +02:00
4764d1536c Content-Patch
All checks were successful
release-tag / release-image (push) Successful in 1m48s
2025-05-07 22:18:02 +02:00
3357061c79 Warum personenbezogene Daten nie in die Betreffzeile einer E‑Mail gehören
All checks were successful
release-tag / release-image (push) Successful in 1m50s
2025-05-07 21:27:53 +02:00
2a63985564 Merge pull request 'Update Datenschutz und Impressum Telefonnummer' (#5) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 1m50s
Reviewed-on: #5
2025-05-07 16:18:58 +00:00
a83e360317 Update Datenschutz und Impressum Telefonnummer
All checks were successful
release-tag / release-image (push) Successful in 1m55s
2025-05-07 18:07:49 +02:00
33c0f9d954 Merge pull request 'staging' (#4) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 1m56s
Reviewed-on: #4
2025-05-06 22:00:17 +00:00
7b598a04be Patch
All checks were successful
release-tag / release-image (push) Successful in 1m52s
2025-05-06 23:34:50 +02:00
8554e13ebf Patch KI-Nutzung und Umsetzung AI-Act
All checks were successful
release-tag / release-image (push) Successful in 1m49s
2025-05-06 23:25:28 +02:00
f6806c5ad0 minor fix
All checks were successful
release-tag / release-image (push) Successful in 1m56s
2025-05-06 22:17:37 +02:00
c0f985982e Anpassung Datenschutz und Nav-Links
All checks were successful
release-tag / release-image (push) Successful in 1m53s
2025-05-06 22:10:58 +02:00
08cb7b689d Merge pull request 'staging' (#3) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 1m50s
Reviewed-on: #3
2025-05-06 18:03:54 +00:00
32d3fc33d6 Merge pull request 'Contentpatch 20250506' (#2) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 1m58s
Reviewed-on: #2
2025-05-06 12:52:51 +00:00
7afa89a66b Merge pull request 'staging' (#1) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 1m55s
Reviewed-on: #1
2025-05-06 10:20:47 +00:00
9 changed files with 392 additions and 36 deletions

View File

@@ -43,9 +43,25 @@ jobs:
with:
context: .
file: ./Dockerfile
build-args: |
CONTENT_REPO=https://git.send.nrw/b1tsblog/blogcontent.git
CONTENT_REF=main
platforms: |
linux/amd64
push: true
tags: | # replace it with your local IP and tags
${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
- name: Build and push StarCitizen
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile
build-args: |
CONTENT_REPO=https://git.send.nrw/b1tsblog/sccontent.git
CONTENT_REF=main
platforms: |
linux/amd64
push: true
tags: | # replace it with your local IP and tags
${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:sc-${{ env.DOCKER_LATEST }}

View File

@@ -48,4 +48,17 @@ jobs:
push: true
tags: | # replace it with your local IP and tags
${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
- name: Build and push StarCitizen
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile
build-args: |
CONTENT_REPO=https://git.send.nrw/b1tsblog/sccontent.git
CONTENT_REF=main
platforms: |
linux/amd64
push: true
tags: | # replace it with your local IP and tags
${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:sc-${{ env.DOCKER_LATEST }}

View File

@@ -27,10 +27,11 @@ RUN git clone --depth 1 --branch ${CONTENT_REF} ${CONTENT_REPO} /src
# • statische Seiten: /pages/* → /out/pages
# (PfadAnpassung hier nach DEINEM RepositoryLayout)
RUN mkdir -p /out/content /out/static /out/pages
RUN mkdir -p /out/content /out/static /out/pages /out/templates/
RUN find /src/articles -name '*.md' -exec cp {} /out/content/ \;
RUN cp -r /src/static/* /out/static/
RUN cp -r /src/pages/* /out/pages/
RUN cp -r /src/templates/* /out/templates/
############################
@@ -40,22 +41,30 @@ FROM debian:bookworm-slim
# (optional) MySQLClient für später
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
ca-certificates git \
&& rm -rf /var/lib/apt/lists/*
# ─── Binärdatei ─────
COPY --from=build /blog /usr/local/bin/blog
# ─── Content + Assets ───
RUN mkdir -p /content /static /pages /app
RUN mkdir -p /content /static /pages /app /templates /ticks
COPY . /app
COPY --from=content /out/content /content
COPY --from=content /out/static /static
COPY --from=content /out/pages /pages
COPY --from=content /out/templates /templates
ENV BLOG_CONTENT_DIR=/content
ENV BLOG_STATIC_DIR=/static
ENV BLOG_PAGES_DIR=/pages
ENV BLOG_TEMPLATES_DIR=/templates
ENV BLOG_TICKS_DIR=/ticks
ENV GIT_ENABLE=false
ENV GIT_REPO=null
ENV GIT_BRANCH=main
ENV GIT_DIR=/git-temp
ENV GIT_INTERVAL=10
EXPOSE 8080
CMD ["blog"]

41
Dockerfile_Slim Normal file
View File

@@ -0,0 +1,41 @@
############################
# 1) GoBuild
############################
FROM golang:1.23.1 AS build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /blog ./cmd/blog
############################
# 3) RuntimeImage
############################
FROM debian:bookworm-slim
# (optional) MySQLClient für später
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates git \
&& rm -rf /var/lib/apt/lists/*
# ─── Binärdatei ─────
COPY --from=build /blog /usr/local/bin/blog
# ─── Content + Assets ───
RUN mkdir -p /content /static /pages /app /templates /ticks /git-temp
COPY . /app
ENV BLOG_CONTENT_DIR=/content
ENV BLOG_STATIC_DIR=/static
ENV BLOG_PAGES_DIR=/pages
ENV BLOG_TEMPLATES_DIR=/templates
ENV BLOG_TICKS_DIR=/ticks
ENV GIT_ENABLE=false
ENV GIT_REPO=null
ENV GIT_BRANCH=main
ENV GIT_DIR=/git-temp
ENV GIT_INTERVAL=10
EXPOSE 8080
CMD ["blog"]

View File

@@ -1,14 +1,25 @@
# b1tsblog
- Warum meldet der Client, dass die DefaultDomainPolicy nicht gelesen werden kann
## B1tsBlog
- Anpassung Datenschutzerklärung
- Windows Server 2025 Domänen-Controller legt Netzwerkprofil auf Öffentlich fest
- TLS-Zertifikat mit SHA3 auf Windows Server 2016 einspielen
- Warum personenbezogene Daten nie in die Betreffzeile einer E-Mail gehören
- Warum meldet der Client, dass die Default Domain Policy nicht gelesen werden kann
- Open Source als Innovationsmotor: Warum Unternehmen auf offene Software setzen
- Neue Blogserie: Open Source im Unternehmen
- Optimiert für schnelleres Laden mit webp-Inhalten
- docker-swarm-mit-abweichendem-port-einrichten
- Content-Update 2025-05-05
- Content-Update 2025-05-05
- PHPMyAdmin mit Serverauswahl im Homelab mittels Docker bereitstellen
- Windows Fehler 0x80072F8F - Installation optionaler Features schlägt fehl
- In Ubuntu den Port 53 - DNS - selber nutzen
- Ein eigenes Docker-Image erstellen - so geht's
- Der eigene DNS-Server im Homelab
- Content-Update 2025-05-04
## B1ts Star Citizen Blog
- Anpassung Datenschutzerklärung
- Invictus 2955 - Das Jahr der Idris-P?

View File

@@ -1,17 +1,74 @@
package main
import (
"encoding/json"
"fmt"
"html/template"
"io"
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
"git.send.nrw/sendnrw/b1tsblog/internal/article"
)
var TickCatalog []TickEntry
func SaveTickCatalog(filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
return encoder.Encode(TickCatalog)
}
func LoadTickCatalog(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
return json.NewDecoder(file).Decode(&TickCatalog)
}
func IncTick(xSlug string) error {
for a, b := range TickCatalog {
if b.Slug == xSlug {
TickCatalog[a].Count = TickCatalog[a].Count + 1
return nil
}
}
newEntry := TickEntry{Slug: xSlug, Count: 1}
TickCatalog = append(TickCatalog, newEntry)
return fmt.Errorf("")
}
func getTick(xSlug string) string {
for _, b := range TickCatalog {
if b.Slug == xSlug {
var n int64 = b.Count
return strconv.FormatInt(n, 10)
}
}
return "0"
}
type TickEntry struct {
Slug string `json:"slug"`
Count int64 `json:"count"`
}
func getenv(k, d string) string {
if v := os.Getenv(k); v != "" {
return v
@@ -39,44 +96,58 @@ var (
tplArticle *template.Template
)
var Xarticles []article.Article
func main() {
// Signal-Kanal einrichten
stop := make(chan os.Signal, 1)
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
// Goroutine, die auf Signale wartet
go func() {
<-stop
fmt.Println("Stop Sign...")
prepareExit()
os.Exit(0)
}()
// --- Verzeichnisse konfigurierbar machen -------------------------
contentDir := os.Getenv("BLOG_CONTENT_DIR")
if contentDir == "" {
contentDir = "/content" // Fallback für local run
contentDir := getenv("BLOG_CONTENT_DIR", "/content")
staticDir := getenv("BLOG_STATIC_DIR", "/app/internal/web/static")
pagesDir := getenv("BLOG_PAGES_DIR", "/pages")
templatesDir := getenv("BLOG_TEMPLATES_DIR", "/templates")
ticksDir := getenv("BLOG_TICKS_DIR", "/ticks")
gitEnable := enabled("GIT_ENABLE", false)
gitRepo := getenv("GIT_REPO", "null")
gitBranch := getenv("GIT_BRANCH", "main")
gitDir := getenv("GIT_DIR", "/git-temp")
gitInterval := getenv("GIT_INTERVAL", "10")
TickCatalog = nil
if err := LoadTickCatalog(ticksDir + "/ticks.json"); err != nil {
fmt.Println("Fehler beim Laden:", err)
}
staticDir := os.Getenv("BLOG_STATIC_DIR")
if staticDir == "" {
staticDir = "/app/internal/web/static"
}
pagesDir := os.Getenv("BLOG_PAGES_DIR")
if staticDir == "" {
staticDir = "/pages"
}
fmt.Println("Geladener Katalog:", TickCatalog)
funcs := template.FuncMap{
"now": time.Now, // jetztZeit bereitstellen
}
// Basislayout zuerst parsen
layout := template.Must(
template.New("base").Funcs(funcs).
ParseFiles("/app/internal/web/templates/base.html"),
)
layout := template.Must(template.New("base").Funcs(funcs).ParseFiles(templatesDir + "/base.html"))
// LISTSeite: base + list.html
tplList = template.Must(layout.Clone())
template.Must(tplList.Funcs(funcs).ParseFiles("/app/internal/web/templates/list.html"))
template.Must(tplList.Funcs(funcs).ParseFiles(templatesDir + "/list.html"))
// ARTICLEInstanz
tplArticle = template.Must(layout.Clone())
template.Must(tplArticle.Funcs(funcs).ParseFiles("/app/internal/web/templates/article.html"))
template.Must(tplArticle.Funcs(funcs).ParseFiles(templatesDir + "/article.html"))
tplPage := template.Must(layout.Clone())
template.Must(tplPage.ParseFiles("/app/internal/web/templates/page.html"))
template.Must(tplPage.ParseFiles(templatesDir + "/page.html"))
mux := http.NewServeMux()
@@ -85,6 +156,8 @@ func main() {
fmt.Println(err)
}
Xarticles = articles
staticPages, err := article.LoadStatic(pagesDir)
if err != nil {
fmt.Println(err)
@@ -98,10 +171,19 @@ func main() {
http.NotFound(w, r)
return
}
/* */
for a, b := range Xarticles {
Xarticles[a].Counter = getTick(b.Slug)
}
/* */
if err := tplList.ExecuteTemplate(w, "layout", article.ListPage{
Title: "Startseite",
Description: "Alle Artikel im Überblick",
Articles: articles,
Articles: Xarticles,
}); err != nil {
http.Error(w, err.Error(), 500)
}
@@ -109,8 +191,11 @@ func main() {
mux.HandleFunc("/post/", func(w http.ResponseWriter, r *http.Request) {
slug := strings.TrimPrefix(r.URL.Path, "/post/")
for _, a := range articles {
for _, a := range Xarticles {
if a.Slug == slug {
IncTick(slug)
t := getTick(slug)
a.Counter = t
if err := tplArticle.ExecuteTemplate(w, "layout", a); err != nil {
http.Error(w, err.Error(), 500)
}
@@ -133,9 +218,188 @@ func main() {
}
})
mux.Handle("/static/",
cacheControl(http.StripPrefix("/static/",
http.FileServer(http.Dir(staticDir)))))
mux.Handle("/static/", cacheControl(http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir)))))
if gitEnable {
xMinute, _ := strconv.Atoi(gitInterval)
xDuration := time.Duration(xMinute) * time.Minute
go startAutoClone(gitRepo, gitBranch, gitDir, xDuration)
}
StopServer(http.ListenAndServe(":8080", mux))
http.ListenAndServe(":8080", mux)
}
func prepareExit() {
fmt.Println("~", "Running exit tasks...")
if err := SaveTickCatalog(getenv("BLOG_TICKS_DIR", "/ticks") + "/ticks.json"); err != nil {
fmt.Println("Fehler beim Speichern:", err)
}
fmt.Println("Geladener Katalog:", TickCatalog)
fmt.Println("~", "Exit completed.")
}
func StopServer(e error) {
fmt.Println("~", "Stopping server...")
prepareExit()
fmt.Println("~", "Server stopped!")
}
func cloneRepo(repoURL, branch, dir string) {
fmt.Printf("Starte Klonvorgang für Branch '%s'...\n", branch)
// Verzeichnis löschen
if err := os.RemoveAll(dir); err != nil {
fmt.Println("Fehler beim Löschen des Verzeichnisses:", err)
return
}
// Git-Clone mit Branch
cmd := exec.Command("git", "clone", "--branch", branch, "--single-branch", repoURL, dir)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Println("Fehler beim Klonen:", err)
} else {
fmt.Println("Repo erfolgreich geklont.")
}
contentDir := getenv("BLOG_CONTENT_DIR", "/content")
err := os.RemoveAll("/content")
if err != nil {
fmt.Println(err, "/content")
}
err = os.RemoveAll("/static")
if err != nil {
fmt.Println(err, "/static")
}
err = os.RemoveAll("/pages")
if err != nil {
fmt.Println(err, "/pages")
}
err = os.RemoveAll("/templates")
if err != nil {
fmt.Println(err, "/templates")
}
if err := os.MkdirAll("/content", 0755); err != nil {
fmt.Println("Fehler beim Erstellen des Zielordners:", err)
return
}
if err := os.MkdirAll("/static", 0755); err != nil {
fmt.Println("Fehler beim Erstellen des Zielordners:", err)
return
}
if err := os.MkdirAll("/pages", 0755); err != nil {
fmt.Println("Fehler beim Erstellen des Zielordners:", err)
return
}
if err := os.MkdirAll("/templates", 0755); err != nil {
fmt.Println("Fehler beim Erstellen des Zielordners:", err)
return
}
if err := copyDirContents("/git-temp/articles", "/content"); err != nil {
fmt.Println("Fehler beim Kopieren:", err)
} else {
fmt.Println("Kopieren abgeschlossen.")
}
if err := copyDirContents("/git-temp/static", "/static"); err != nil {
fmt.Println("Fehler beim Kopieren:", err)
} else {
fmt.Println("Kopieren abgeschlossen.")
}
if err := copyDirContents("/git-temp/pages", "/pages"); err != nil {
fmt.Println("Fehler beim Kopieren:", err)
} else {
fmt.Println("Kopieren abgeschlossen.")
}
if err := copyDirContents("/git-temp/templates", "/templates"); err != nil {
fmt.Println("Fehler beim Kopieren:", err)
} else {
fmt.Println("Kopieren abgeschlossen.")
}
articles, err := article.LoadDir(contentDir)
if err != nil {
fmt.Println(err)
}
Xarticles = articles
}
func copyDirContents(srcDir, destDir string) error {
entries, err := os.ReadDir(srcDir)
if err != nil {
return fmt.Errorf("Fehler beim Lesen von %s: %w", srcDir, err)
}
for _, entry := range entries {
srcPath := filepath.Join(srcDir, entry.Name())
destPath := filepath.Join(destDir, entry.Name())
info, err := entry.Info()
if err != nil {
return err
}
if info.IsDir() {
if err := os.MkdirAll(destPath, info.Mode()); err != nil {
return fmt.Errorf("Fehler beim Erstellen von Ordner %s: %w", destPath, err)
}
// rekursiv kopieren
if err := copyDirContents(srcPath, destPath); err != nil {
return err
}
} else {
if err := copyFile(srcPath, destPath, info); err != nil {
return err
}
}
}
return nil
}
func copyFile(src, dest string, info os.FileInfo) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dest)
if err != nil {
return err
}
defer out.Close()
if _, err := io.Copy(out, in); err != nil {
return err
}
return os.Chmod(dest, info.Mode())
}
func startAutoClone(repoURL, branch, dir string, interval time.Duration) {
go cloneRepo(repoURL, branch, dir) // sofortiger Start
ticker := time.NewTicker(interval)
defer ticker.Stop()
for range ticker.C {
go cloneRepo(repoURL, branch, dir)
}
}

View File

@@ -13,6 +13,7 @@ type Article struct {
Cover string
Body template.HTML
Description string
Counter string
}
type ListPage struct {

View File

@@ -16,10 +16,11 @@
<h1><a href="/" class="no-underline">B1tsblog</a></h1>
<nav class="main-nav">
<ul>
<li><a class="no-underline" href="/">Startseite</a></li>
<li><a class="no-underline" href="/page/welcome">Hallo! und Datenschutz</a></li>
<li><a class="no-underline" href="/">Start</a></li>
<li><a class="no-underline" href="/page/welcome">Hallo</a></li>
<li><a class="no-underline" href="/page/ai">KI</a></li>
<li><a class="no-underline" href="/page/datenschutzerklaerung">Datenschutz</a></li>
<li><a class="no-underline" href="/page/impressum">Impressum</a></li>
<!-- später: <li><a href="/page/datenschutz">Datenschutz</a></li> -->
</ul>
</nav>
</header>

View File

@@ -10,7 +10,7 @@
{{ end }}
<div class="card-content">
<h2>{{ .Title }}</h2>
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "02.01.2006" }}</time>
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "02.01.2006" }}</time> ({{ .Counter }})
</div>
</a>
</li>