diff --git a/cmd/web/web.go b/cmd/web/web.go
index 9ecf60c..665162c 100644
--- a/cmd/web/web.go
+++ b/cmd/web/web.go
@@ -1,68 +1,23 @@
package main
import (
- "fmt"
- "gitlab.com/kbr4/svevijesti/internal/database"
- "html/template"
- "io/ioutil"
+ "gitlab.com/kbr4/svevijesti/internal/server"
+ "log"
"net/http"
- "path/filepath"
- "strings"
"time"
)
-var tPath = "./web/tpl/"
-var dPath = "./web/data/"
-
-var templateDirs = []string{"./web/tpl", "./web/data"}
-var templates *template.Template
-
-func getTemplates() (templates *template.Template, err error) {
- var allFiles []string
- for _, dir := range templateDirs {
- files2, _ := ioutil.ReadDir(dir)
- for _, file := range files2 {
- filename := file.Name()
- if strings.HasSuffix(filename, ".html") {
- filePath := filepath.Join(dir, filename)
- fmt.Println("Template found: ", filePath)
- allFiles = append(allFiles, filePath)
- }
- }
- }
-
- templates, err = template.New("").ParseFiles(allFiles...)
- return
-}
-
-func init() {
- templates, _ = getTemplates()
-}
-
-func rootHandler(wr http.ResponseWriter, req *http.Request) {
- title := "Pocetna"
- store, err := database.Connect()
- if err != nil {
- http.Error(wr, err.Error(), http.StatusInternalServerError)
- }
-
- articles, err := database.ArticlesForDay(store, time.Now())
- if err != nil {
- http.Error(wr, err.Error(), http.StatusInternalServerError)
- }
-
- data := map[string]interface{}{
- "title": title,
- "articles": articles,
- }
-
- err = templates.ExecuteTemplate(wr, "homeHTML", data)
- if err != nil {
- http.Error(wr, err.Error(), http.StatusInternalServerError)
- }
-}
-
func main() {
- http.HandleFunc("/", rootHandler)
- http.ListenAndServe(":8080", nil)
+ r := server.CreateRoutes()
+ http.Handle("/", r)
+
+ srv := &http.Server{
+ Handler: r,
+ Addr: "0.0.0.0:8080",
+ // Good practice: enforce timeouts for servers you create!
+ WriteTimeout: 15 * time.Second,
+ ReadTimeout: 15 * time.Second,
+ }
+
+ log.Fatal(srv.ListenAndServe())
}
diff --git a/go.mod b/go.mod
index 4eac5ae..a5b4e5d 100644
--- a/go.mod
+++ b/go.mod
@@ -12,6 +12,7 @@ require (
github.com/gocolly/colly v1.2.0 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.3.1 // indirect
+ github.com/gorilla/mux v1.8.0 // indirect
github.com/gosimple/slug v1.12.0 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/kennygrant/sanitize v1.2.4 // indirect
diff --git a/go.sum b/go.sum
index f092c10..b68be6c 100644
--- a/go.sum
+++ b/go.sum
@@ -19,6 +19,8 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18h
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gosimple/slug v1.12.0 h1:xzuhj7G7cGtd34NXnW/yF0l+AGNfWqwgh/IXgFy7dnc=
github.com/gosimple/slug v1.12.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
diff --git a/internal/database/articles.go b/internal/database/articles.go
index 65c6df2..64e0dab 100644
--- a/internal/database/articles.go
+++ b/internal/database/articles.go
@@ -4,7 +4,9 @@ import (
"fmt"
_ "github.com/lib/pq"
"gitlab.com/kbr4/svevijesti/internal/model"
+ "html/template"
"math"
+ "strings"
"time"
)
@@ -86,3 +88,45 @@ func ArticlesForDay(store *Store, day time.Time) (articles []model.DisplayArticl
return result, nil
}
+
+func ArticleByID(store *Store, ID int, slug string) (article model.DisplayArticle, err error) {
+
+ result := model.DisplayArticle{}
+ query, err := store.Prepare(`
+ select id,title, content, slug, original_url, source_id, created_at from articles where id = $1 and slug = $2;
+ `)
+ if err != nil {
+ return result, err
+ }
+
+ row := query.QueryRow(ID, slug)
+ if err != nil {
+ return result, err
+ }
+
+ r := model.DisplayArticle{}
+ content := ""
+ err = row.Scan(&r.ID, &r.Title, &content, &r.Slug, &r.OriginalUrl, &r.SourceId, &r.CreatedAt)
+ if err != nil {
+ return result, err
+ }
+
+ ago := time.Now().Sub(r.CreatedAt)
+ hours := ago.Hours()
+
+ r.Content = template.HTML(strings.Replace(content, "\n", "
\n", -1))
+
+ if hours < 1 {
+ r.FormatedCreatedAt = fmt.Sprintf("Prije %d minuta.", int(math.Floor(ago.Minutes())))
+
+ } else if hours > 24 {
+ r.FormatedCreatedAt = r.CreatedAt.Format("01.02.2006. 15:04:05")
+ } else {
+ r.FormatedCreatedAt = fmt.Sprintf("Prije %d sati.", int(math.Floor(hours)))
+ }
+ r.SourceName = model.SourceName(r.SourceId)
+
+ result = r
+
+ return result, nil
+}
diff --git a/internal/model/model.go b/internal/model/model.go
index 29aa6c7..d9211fb 100644
--- a/internal/model/model.go
+++ b/internal/model/model.go
@@ -1,6 +1,9 @@
package model
-import "time"
+import (
+ "html/template"
+ "time"
+)
type ScrapedArticle struct {
Title string
@@ -13,7 +16,7 @@ type ScrapedArticle struct {
type DisplayArticle struct {
ID int
Title string
- Content string
+ Content template.HTML
Slug string
OriginalUrl string
SourceId int
diff --git a/internal/server/articles.go b/internal/server/articles.go
new file mode 100644
index 0000000..c28f897
--- /dev/null
+++ b/internal/server/articles.go
@@ -0,0 +1,61 @@
+package server
+
+import (
+ "github.com/gorilla/mux"
+ "gitlab.com/kbr4/svevijesti/internal/database"
+ "net/http"
+ "strconv"
+ "time"
+)
+
+func rootHandler(wr http.ResponseWriter, req *http.Request) {
+ title := "Pocetna"
+ store, err := database.Connect()
+ if err != nil {
+ http.Error(wr, err.Error(), http.StatusInternalServerError)
+ }
+
+ articles, err := database.ArticlesForDay(store, time.Now())
+ if err != nil {
+ http.Error(wr, err.Error(), http.StatusInternalServerError)
+ }
+
+ data := map[string]interface{}{
+ "title": title,
+ "articles": articles,
+ }
+
+ err = templates.ExecuteTemplate(wr, "homeHTML", data)
+ if err != nil {
+ http.Error(wr, err.Error(), http.StatusInternalServerError)
+ }
+}
+
+func articleHandler(wr http.ResponseWriter, req *http.Request) {
+ title := "Pocetna"
+ store, err := database.Connect()
+ if err != nil {
+ http.Error(wr, err.Error(), http.StatusInternalServerError)
+ }
+
+ vars := mux.Vars(req)
+ articleID, err := strconv.Atoi(vars["id"])
+ if err != nil {
+ articleID = -1
+ }
+ articleSlug := vars["slug"]
+ article, err := database.ArticleByID(store, articleID, articleSlug)
+ if err != nil {
+ http.Error(wr, err.Error(), http.StatusNotFound)
+ }
+
+ data := map[string]interface{}{
+ "title": title,
+ "article": article,
+ }
+
+ err = templates.ExecuteTemplate(wr, "articleHTML", data)
+ if err != nil {
+ http.Error(wr, err.Error(), http.StatusInternalServerError)
+ }
+}
diff --git a/internal/server/server.go b/internal/server/server.go
index abb4e43..90cb0c8 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -1 +1,45 @@
package server
+
+import (
+ "fmt"
+ "github.com/gorilla/mux"
+ "html/template"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+)
+
+var tPath = "./web/tpl/"
+var dPath = "./web/data/"
+
+var templateDirs = []string{"./web/tpl", "./web/data"}
+var templates *template.Template
+
+func getTemplates() (templates *template.Template, err error) {
+ var allFiles []string
+ for _, dir := range templateDirs {
+ files2, _ := ioutil.ReadDir(dir)
+ for _, file := range files2 {
+ filename := file.Name()
+ if strings.HasSuffix(filename, ".html") {
+ filePath := filepath.Join(dir, filename)
+ fmt.Println("Template found: ", filePath)
+ allFiles = append(allFiles, filePath)
+ }
+ }
+ }
+
+ templates, err = template.New("").ParseFiles(allFiles...)
+ return
+}
+
+func init() {
+ templates, _ = getTemplates()
+}
+
+func CreateRoutes() *mux.Router {
+ r := mux.NewRouter()
+ r.HandleFunc("/", rootHandler)
+ r.HandleFunc("/{id:[0-9]+}/{slug}", articleHandler)
+ return r
+}
diff --git a/web/data/footer.html b/web/data/footer.html
index 80b8f37..a34300b 100644
--- a/web/data/footer.html
+++ b/web/data/footer.html
@@ -1,6 +1,6 @@
{{define "footerHTML"}}
{{end}}
diff --git a/web/data/head.html b/web/data/head.html
index 8c66df4..bf43e1e 100644
--- a/web/data/head.html
+++ b/web/data/head.html
@@ -20,8 +20,20 @@
max-width: 98vw;
}
+ h1#title {
+ margin-block-end: 0;
+ font-size: 1.7em;
+ }
+
.timestamp {
font-size: 0.8em;
+ color: gray;
+ }
+
+ .single_timestamp {
+ font-size: 0.77em;
+ margin-bottom: 0.7em;
+ color: gray;
}
#logo {
diff --git a/web/data/single_article.html b/web/data/single_article.html
new file mode 100644
index 0000000..5c30b30
--- /dev/null
+++ b/web/data/single_article.html
@@ -0,0 +1,11 @@
+{{define "singleArticleHTML"}}
+{{with .article }}
+