summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhyscik <mynameisgennadiy@vk.com>2025-12-26 20:08:28 +0500
committerPhyscik <mynameisgennadiy@vk.com>2025-12-26 20:08:28 +0500
commitfb2adbb65087252c0fd0392c8fa8f0218bffa22b (patch)
tree609f9b0604179d29613735e76d70df30357315d8
parent424c95749a12b57caeba7c3ecd5034daacf5a651 (diff)
Articles idnexing
m---------articles0
-rw-r--r--db.sql19
-rw-r--r--src/Index/Connection.go89
-rw-r--r--src/Render/Render.go54
-rw-r--r--src/Settings.json3
-rw-r--r--src/Settings/Settings.go2
-rw-r--r--src/go.mod2
-rw-r--r--src/go.sum2
-rw-r--r--src/main.go2
-rw-r--r--static/common.js8
-rw-r--r--templates/index.html16
11 files changed, 174 insertions, 23 deletions
diff --git a/articles b/articles
-Subproject 7586257fd5767bca2c3e939c05e7e51f052f8a7
+Subproject 28d1b19d519b55aaa39a145c631df6f84ba099b
diff --git a/db.sql b/db.sql
new file mode 100644
index 0000000..06db73b
--- /dev/null
+++ b/db.sql
@@ -0,0 +1,19 @@
+CREATE TABLE Articles (
+ Id INTEGER PRIMARY KEY AUTOINCREMENT,
+ DisplayName TEXT UNIQUE,
+ FileName TEXT UNIQUE,
+ URL TEXT UNIQUE,
+ CreatedAt TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE TABLE Tags (
+ Id INTEGER PRIMARY KEY AUTOINCREMENT,
+ Name TEXT
+);
+
+CREATE TABLE ArticlesToTags (
+ ArticleId INTEGER,
+ TagId INTEGER,
+ FOREIGN KEY(ArticleId) REFERENCES Articles(Id),
+ FOREIGN KEY(TagId) REFERENCES Tags(Id)
+);
diff --git a/src/Index/Connection.go b/src/Index/Connection.go
new file mode 100644
index 0000000..d4523b2
--- /dev/null
+++ b/src/Index/Connection.go
@@ -0,0 +1,89 @@
+package index
+
+import (
+ "database/sql"
+ "fmt"
+ "log/slog"
+ _ "github.com/mattn/go-sqlite3"
+
+ settings "physick.ru/Settings"
+)
+
+var db *sql.DB = nil
+
+type Article struct {
+ Id int
+ DisplayName string
+ FileName string
+ URL string
+
+ Tags []Tag
+}
+
+type Tag struct {
+ Id int
+ Name string
+}
+
+func EstablistDBConnection() {
+ var database, err = sql.Open("sqlite3", settings.Current.IndexDB)
+ if err != nil {
+ panic(fmt.Sprintf("Failed to start a server: DB connection failed (%s)", err.Error()))
+ }
+ db = database
+}
+
+func GetAllArticles() ([]Article, error) {
+ var rows, sqlErr = db.Query("SELECT Id, DisplayName, FileName, URL FROM Articles;")
+ if sqlErr != nil {
+ return []Article{}, sqlErr
+ }
+ var outp = make([]Article, 0)
+ for rows.Next() {
+ var new = Article{}
+ rows.Scan(&new.Id, &new.DisplayName, &new.FileName, &new.URL)
+ var tagsErr = new.FillTags()
+ if tagsErr != nil {
+ slog.Warn("Failed to parse article flags", slog.Any("Error", tagsErr))
+ }
+ outp = append(outp, new)
+ }
+ return outp, nil
+}
+
+func (base *Article) FillTags() error {
+ var rows, sqlErr = db.Query(`SELECT Tags.Id, Tags.Name
+ FROM ArticlesToTags LEFT JOIN Tags ON Tags.Id = ArticlesToTags.TagId
+ WHERE ArticlesToTags.ArticleId = ?;`, base.Id)
+ if sqlErr != nil {
+ return sqlErr
+ }
+ var outp = make([]Tag, 0)
+ for rows.Next() {
+ var new = Tag{}
+ var err = rows.Scan(&new.Id, &new.Name)
+ if err != nil {
+ slog.Warn("Failed to parse a tag descriptor from the table", slog.Any("Error", err))
+ }
+ outp = append(outp, new)
+ }
+ base.Tags = outp
+ return nil
+}
+
+func GetArticleByName(URL string) (Article, error) {
+ var rows, sqlErr = db.Query("SELECT Id, DisplayName, FileName, URL FROM Articles WHERE URL = ?;", URL)
+ if sqlErr != nil {
+ return Article{}, sqlErr
+ }
+ var new = Article{}
+ for rows.Next() {
+ rows.Scan(&new.Id, &new.DisplayName, &new.FileName, &new.URL)
+ var tagsErr = new.FillTags()
+ if tagsErr != nil {
+ slog.Error("Failed to parse article flags", slog.Any("Error", tagsErr))
+ }
+ }
+ return new, nil
+
+}
diff --git a/src/Render/Render.go b/src/Render/Render.go
index bdaa51e..130789c 100644
--- a/src/Render/Render.go
+++ b/src/Render/Render.go
@@ -6,17 +6,14 @@ import (
"net/http"
"strings"
+ index "physick.ru/Index"
settings "physick.ru/Settings"
)
type IndexTemplateContents struct {
- LastArticles []recentArticle
+ LastArticles []index.Article
Content string
-}
-
-type recentArticle struct {
- Link string
- DisplayName string
+ Tags []index.Tag
}
func RegisterEndpoints() {
@@ -45,17 +42,48 @@ func common(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
return
}
+ var recentArticles, dbErr = index.GetAllArticles()
+ if dbErr != nil {
+ slog.Error("Failed to get recent articles from database", slog.Any("Error", dbErr))
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
executeIndexTemplate(IndexTemplateContents{
- LastArticles: []recentArticle {
- recentArticle {
- Link: "/",
- DisplayName: "Index page",
- },
- },
+ LastArticles: recentArticles,
Content: indexArticle,
}, w)
}
func test(w http.ResponseWriter, r *http.Request) {
- fmt.Fprint(w, "xdx")
+ var requestedName = r.PathValue("name")
+ if len(requestedName) < 1 {
+ w.WriteHeader(http.StatusNotFound)
+ return
+ }
+ var article, dbErr = index.GetArticleByName(requestedName)
+ if dbErr != nil {
+ slog.Error("Failed to get an article from db", slog.Any("Error", dbErr))
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ if len(article.DisplayName) < 1 {
+ w.WriteHeader(http.StatusNotFound)
+ return
+ }
+ var contents, fileErr = getTemplate(article.FileName)
+ if fileErr != nil {
+ w.WriteHeader(http.StatusNotFound)
+ return
+ }
+ var recentArticles, err = index.GetAllArticles()
+ if err != nil {
+ slog.Error("Failed to get recent articles from database", slog.Any("Error", err))
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ executeIndexTemplate(IndexTemplateContents{
+ LastArticles: recentArticles,
+ Content: contents,
+ Tags: article.Tags,
+ }, w)
}
diff --git a/src/Settings.json b/src/Settings.json
index acd7ab3..9700828 100644
--- a/src/Settings.json
+++ b/src/Settings.json
@@ -2,5 +2,6 @@
"Port": ":7000",
"StaticLocation": "../static",
"TemplatesLocation": "../templates",
- "ArticlesLocation": "../articles"
+ "ArticlesLocation": "../articles",
+ "IndexDB": "../articles/index.db"
}
diff --git a/src/Settings/Settings.go b/src/Settings/Settings.go
index 50df787..8c64442 100644
--- a/src/Settings/Settings.go
+++ b/src/Settings/Settings.go
@@ -12,6 +12,7 @@ type Settings struct {
StaticLocation string
TemplatesLocation string
ArticlesLocation string
+ IndexDB string
}
const settingsLocation = "Settings.json"
@@ -21,6 +22,7 @@ var defaultSettings = Settings {
StaticLocation: "../static",
TemplatesLocation: "../templates",
ArticlesLocation: "../articles",
+ IndexDB: "../articles/index.db",
}
diff --git a/src/go.mod b/src/go.mod
index 27c0362..d6b9df7 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -1,3 +1,5 @@
module physick.ru
go 1.25.4
+
+require github.com/mattn/go-sqlite3 v1.14.32 // indirect
diff --git a/src/go.sum b/src/go.sum
new file mode 100644
index 0000000..66f7516
--- /dev/null
+++ b/src/go.sum
@@ -0,0 +1,2 @@
+github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
+github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
diff --git a/src/main.go b/src/main.go
index c950f14..fdcfef8 100644
--- a/src/main.go
+++ b/src/main.go
@@ -4,12 +4,14 @@ import (
"log/slog"
"net/http"
+ index "physick.ru/Index"
render "physick.ru/Render"
settings "physick.ru/Settings"
)
func main() {
settings.ReadSettings()
+ index.EstablistDBConnection()
render.RegisterEndpoints()
diff --git a/static/common.js b/static/common.js
index a7dc3a5..bf98cea 100644
--- a/static/common.js
+++ b/static/common.js
@@ -13,15 +13,15 @@ function ToggleMode() {
function setLightMode() {
swapClasses("dark", "light");
localStorage.setItem("theme", "light");
- document.getElementById("toggleIcon").src = "static/toggle.svg"
- document.getElementById("homeIcon").src = "static/home_dark.svg"
+ document.getElementById("toggleIcon").src = "/static/toggle.svg"
+ document.getElementById("homeIcon").src = "/static/home_dark.svg"
}
function setDarkMode() {
swapClasses("light", "dark");
localStorage.setItem("theme", "dark");
- document.getElementById("toggleIcon").src = "static/toggle_dark.svg"
- document.getElementById("homeIcon").src = "static/home.svg"
+ document.getElementById("toggleIcon").src = "/static/toggle_dark.svg"
+ document.getElementById("homeIcon").src = "/static/home.svg"
}
function swapClasses(baseClass, newClass) {
diff --git a/templates/index.html b/templates/index.html
index 250f509..16377d2 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -4,26 +4,32 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Space+Grotesk:wght@300..700&display=swap" rel="stylesheet">
- <link href="static/common.css" rel="stylesheet" />
- <script src="static/common.js"></script>
+ <link href="/static/common.css" rel="stylesheet" />
+ <script src="/static/common.js"></script>
</head>
<body class="dark">
<div id="menu" class="dark">
<div class="control">
<a href="/">
- <img id="homeIcon" src="static/home.svg" height="40px" width="40px">
+ <img id="homeIcon" src="/static/home.svg" height="40px" width="40px">
</a>
<button class="toggleBtn" onclick="ToggleMode()">
- <img id="toggleIcon" src="static/toggle_dark.svg" height="48px" width="48px">
+ <img id="toggleIcon" src="/static/toggle_dark.svg" height="48px" width="48px">
</button>
</div>
<h2> Recent articles </h2>
<ul class="articleList dark">
{{ range .LastArticles}}
- <li> <a href={{ .Link }}> {{ .DisplayName }} </a> </li>
+ <li> <a href="/articles/{{ .URL }}"> {{ .DisplayName }} </a> </li>
{{ end }}
</ul>
<hr />
+ <h2> Related tags </h2>
+ <ul class="articleList dark">
+ {{ range .Tags}}
+ <li> <a> {{ .Name }} </a> </li>
+ {{ end }}
+ </ul>
</div>
<div id="content" class="dark">
{{.Content}}