diff options
| author | Physcik <mynameisgennadiy@vk.com> | 2025-12-26 20:08:28 +0500 |
|---|---|---|
| committer | Physcik <mynameisgennadiy@vk.com> | 2025-12-26 20:08:28 +0500 |
| commit | fb2adbb65087252c0fd0392c8fa8f0218bffa22b (patch) | |
| tree | 609f9b0604179d29613735e76d70df30357315d8 | |
| parent | 424c95749a12b57caeba7c3ecd5034daacf5a651 (diff) | |
Articles idnexing
| m--------- | articles | 0 | ||||
| -rw-r--r-- | db.sql | 19 | ||||
| -rw-r--r-- | src/Index/Connection.go | 89 | ||||
| -rw-r--r-- | src/Render/Render.go | 54 | ||||
| -rw-r--r-- | src/Settings.json | 3 | ||||
| -rw-r--r-- | src/Settings/Settings.go | 2 | ||||
| -rw-r--r-- | src/go.mod | 2 | ||||
| -rw-r--r-- | src/go.sum | 2 | ||||
| -rw-r--r-- | src/main.go | 2 | ||||
| -rw-r--r-- | static/common.js | 8 | ||||
| -rw-r--r-- | templates/index.html | 16 |
11 files changed, 174 insertions, 23 deletions
diff --git a/articles b/articles -Subproject 7586257fd5767bca2c3e939c05e7e51f052f8a7 +Subproject 28d1b19d519b55aaa39a145c631df6f84ba099b @@ -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", } @@ -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}} |
