diff --git a/main.go b/main.go
index d2d550a..531713c 100644
--- a/main.go
+++ b/main.go
@@ -1,82 +1,26 @@
package main
import (
- "crypto/sha512"
- "encoding/hex"
- "encoding/json"
- "fmt"
"html/template"
+ "igar/storage"
"io"
- "io/ioutil"
- "mime"
"net/http"
- "os"
- "os/exec"
- "sort"
- "strconv"
"strings"
- "sync"
- "time"
"github.com/google/uuid"
- "github.com/gorilla/feeds"
"github.com/labstack/echo"
- "github.com/labstack/echo/middleware"
//"github.com/labstack/echo/middleware"
)
type (
- JSTime time.Time
-
- Media struct {
- Type string `json:"type"`
- File string `json:"file"`
- Height int `json:"height"`
- Width int `json:"width"`
- }
-
- Entry struct {
- Date JSTime `json:"date"`
- Description string `json:"description"`
- Post string `json:"post"`
- Likes int `json:"likes"`
- Tags []string `json:"tags"`
- Media []Media `json:"media"`
- Prev *Entry `json:"-"`
- Next *Entry `json:"-"`
- // Users []string
- }
- Response struct {
- Ok bool
- Message string
- }
TemplateRenderer struct {
template *template.Template
}
)
-type (
- entryMap struct {
- filename string
- modtime time.Time
- mapped map[string]*Entry
- sorted []*Entry
- mu sync.Mutex
- }
- entryList []*Entry
-)
-
-const (
- jsTimeLite = "2006-01-02"
- jsTimeLayout = "2006-01-02 15:04:05"
- adminUsername = "danolo"
- adminPassword = "bd4cad796950f50352225de3c773d8f3c39622bc17f34ad661eabe615cdf6d32751c5751e0648dc17d890f40330018334a2ae899878f200f6dc80121ddb70cc9"
-)
-
var (
- list *entryMap = &entryMap{
- filename: "img/list.json",
- modtime: time.Unix(0, 0),
+ list *storage.EntryMap = &storage.EntryMap{
+ Filename: "img/list.json",
}
)
@@ -86,224 +30,23 @@ func genName() string {
return strings.Replace(uuid.New().String(), "-", "", -1)
}
-// JSTime
-
-func (ct *JSTime) UnmarshalJSON(b []byte) (err error) {
- s := strings.Trim(string(b), `"`)
- nt, err := time.Parse(jsTimeLayout, s)
- *ct = JSTime(nt)
- return
-}
-
-func (ct JSTime) MarshalJSON() ([]byte, error) {
- return []byte(ct.String()), nil
-}
-
-func (ct JSTime) String() string {
- t := time.Time(ct)
- return fmt.Sprintf("%q", t.Format(jsTimeLayout))
-}
-
-func (ct JSTime) Unix() int64 {
- return time.Time(ct).Unix()
-}
-
-// Entry
-
-func (entry Entry) Count() map[string]int {
- count := make(map[string]int)
- for _, media := range entry.Media {
- count[media.Type] += 1
- }
- return count
-}
-
-func (entry Entry) Len() int { return len(entry.Media) }
-
// TemplateRenderer
func (renderer *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
return renderer.template.ExecuteTemplate(w, name, data)
}
-// entryMap
-
-func (list *entryMap) Len() int { return len(list.mapped) }
-
-func (list *entryMap) modified() (mod bool) {
- info, err := os.Stat(list.filename)
+func IndexController(c echo.Context) (err error) {
+ entries, err := list.GetEntries()
if err == nil {
- mod = list.modtime.Before(info.ModTime())
- list.modtime = info.ModTime()
- } else {
- mod = true
+ err = c.Render(http.StatusOK, "index.html", entries)
}
return
}
-func (list *entryMap) write() (err error) {
- data, err := json.MarshalIndent(list.mapped, "", " ")
- if err == nil {
- err = ioutil.WriteFile(list.filename, data, 0644)
- }
- return
-}
-
-func (list *entryMap) read() (err error) {
- if list.modified() {
- if data, err := ioutil.ReadFile(list.filename); err == nil {
-
- // read map
- list.mapped = make(map[string]*Entry)
- err = json.Unmarshal(data, &list.mapped)
-
- // sort list
- list.sorted = make([]*Entry, 0, len(list.mapped))
- for _, entry := range list.mapped {
- list.sorted = append(list.sorted, entry)
- }
- sort.Sort(entryList(list.sorted))
-
- // assign prev/next
- for index, value := range list.sorted {
- if index-1 >= 0 {
- value.Next = list.sorted[index-1]
- }
- if index+1 < len(list.sorted) {
- value.Prev = list.sorted[index+1]
- }
- }
- }
- }
- return
-}
-
-func (list *entryMap) getSortedEntries() entryList {
- list.mu.Lock()
- defer list.mu.Unlock()
-
- list.read()
-
- return entryList(list.sorted)
-}
-
-func (list *entryMap) readSliceList(oval int, nval int) (result entryList, err error) {
- if nval <= 0 {
- nval = list.Len()
- }
-
- if oval <= 0 {
- oval = 0
- }
-
- if err == nil {
- entries := list.getSortedEntries()
- if oval >= list.Len() {
- result = nil
- } else if oval+nval >= list.Len() {
- result = entries[oval:]
- } else {
- result = entries[oval : oval+nval]
- }
- }
-
- return
-}
-
-func (list *entryMap) addEntry(entry *Entry) (err error) {
- list.mu.Lock()
- defer list.mu.Unlock()
-
- list.read()
-
- if entry != nil {
- list.mapped[entry.Post] = entry
- err = list.write()
- }
-
- return
-}
-
-func (list *entryMap) getEntry(uuid string) (result *Entry, err error) {
- list.mu.Lock()
- defer list.mu.Unlock()
-
- if err = list.read(); err == nil {
- result = list.mapped[uuid]
- }
-
- return
-}
-
-func (list *entryMap) getFeed() (feed *feeds.Feed) {
- feed = &feeds.Feed{
- Title: "danoloan.es igar",
- Link: &feeds.Link{Href: "https://danoloan.es/igar/"},
- Description: "bitácora fotográfica de danoloan",
- Author: &feeds.Author{Name: "danoloan", Email: "danolo@danoloan.es"},
- }
-
- feed.Items = make([]*feeds.Item, 0, list.Len())
- for _, elem := range list.getSortedEntries() {
- item := &feeds.Item{
- Title: elem.Description,
- Link: &feeds.Link{Href: fmt.Sprintf("https://danoloan.es/igar/view?uuid=%s", elem.Post)},
- Description: fmt.Sprintf("
%s
\n\n", elem.Description),
- Created: time.Time(elem.Date),
- }
-
- for _, media := range elem.Media {
- if media.Type == "GraphImage" {
- // TODO ruta relativa al proxy
- item.Description = fmt.Sprintf("%s\n\t
", item.Description, elem.Post, media.File)
- }
- }
- item.Description = fmt.Sprintf("%s\n
", item.Description)
-
- feed.Items = append(feed.Items, item)
- }
-
- return
-}
-
-// entryList
-
-func (list entryList) Len() int { return len(list) }
-func (list entryList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
-func (list entryList) Less(i, j int) bool {
- return time.Time(list[i].Date).After(time.Time(list[j].Date))
-}
-
-// CONTROLLERS
-
-func ListController(c echo.Context) (res error) {
- var err error
- var oval, nval int
-
- oval, err = strconv.Atoi(c.QueryParam("o"))
- if err != nil {
- oval = 0
- }
-
- nval, err = strconv.Atoi(c.QueryParam("n"))
- if err != nil {
- nval = 0
- }
-
- slice, err := list.readSliceList(oval, nval)
- if err == nil {
- res = c.JSON(http.StatusOK, slice)
- } else {
- response := Response{false, "Error fetching song list"}
- res = c.JSON(http.StatusInternalServerError, response)
- }
-
- return
-}
-
func ViewController(c echo.Context) (err error) {
uuid := c.QueryParam("uuid")
- entry, err := list.getEntry(uuid)
+ entry, err := list.GetEntry(uuid)
if err == nil {
err = c.Render(http.StatusOK, "view.html", entry)
}
@@ -313,100 +56,6 @@ func ViewController(c echo.Context) (err error) {
return
}
-func RSSController(c echo.Context) (err error) {
- if blob, err := list.getFeed().ToRss(); err == nil {
- c.Blob(http.StatusOK, "application/xml", []byte(blob))
- }
- return
-}
-
-func JSONController(c echo.Context) (err error) {
- if blob, err := list.getFeed().ToJSON(); err == nil {
- c.Blob(http.StatusOK, "application/json", []byte(blob))
- }
- return
-}
-
-func AtomController(c echo.Context) (err error) {
- if blob, err := list.getFeed().ToAtom(); err == nil {
- c.Blob(http.StatusOK, "application/xml", []byte(blob))
- }
- return
-}
-
-// TODO pura mierda
-func PostController(c echo.Context) (err error) {
- desc := c.FormValue("desc")
- date := c.FormValue("date")
-
- file, err := c.FormFile("file")
-
- entry := &Entry{
- Description: desc,
- Post: genName(),
- }
-
- if date != "" {
- time, _ := time.Parse(jsTimeLite, date)
- entry.Date = JSTime(time)
- } else {
- entry.Date = JSTime(time.Now())
- }
-
- if err != nil {
- return
- }
-
- media := Media{
- Type: "GraphImage",
- File: genName(),
- }
-
- extension, err := mime.ExtensionsByType(file.Header.Get("Content-Type"))
- if err == nil {
- media.File = fmt.Sprintf("%s%s", media.File, extension[0])
- }
-
- entry.Media = append(entry.Media, media)
-
- src, err := file.Open()
- if err != nil {
- return
- }
- defer src.Close()
-
- postdir := fmt.Sprintf("img/%s", entry.Post)
- filepath := fmt.Sprintf("%s/%s", postdir, media.File)
-
- os.MkdirAll(postdir, os.ModePerm)
- dst, err := os.Create(filepath)
- if err != nil {
- return
- }
- defer dst.Close()
-
- list.addEntry(entry)
-
- if _, err = io.Copy(dst, src); err != nil {
- return
- }
-
- if err = exec.Command("node", "thumbs/make_thumb.js", postdir).Run(); err != nil {
- c.Logger().Error(err.Error())
- }
-
- return c.String(http.StatusCreated, "")
-}
-
-func auth(username, password string, c echo.Context) (bool, error) {
- hash := sha512.Sum512([]byte(password))
- hashString := hex.EncodeToString(hash[:])
- if username == adminUsername && hashString == adminPassword {
- return true, nil
- }
- return false, nil
-}
-
func main() {
e := echo.New()
@@ -414,29 +63,25 @@ func main() {
template: template.Must(template.ParseGlob("templates/*.html")),
}
- e.Static("/", "index.html")
-
- e.GET("/list", ListController)
+ e.GET("/", IndexController)
e.GET("/view", ViewController)
- e.GET("/rss", RSSController)
- e.GET("/json", JSONController)
- e.GET("/atom", AtomController)
+ //e.GET("/list", server.ListController)
+
+ //e.GET("/rss", server.RSSController)
+ //e.GET("/json", server.JSONController)
+ //e.GET("/atom", server.AtomController)
e.Static("/static", "static")
e.Static("/img", "img")
- admin := e.Group("/admin", middleware.BasicAuth(auth))
+ //admin := e.Group("/admin", middleware.BasicAuth(auth))
- admin.GET("/", func(c echo.Context) error {
- return c.Render(http.StatusOK, "admin.html", struct{ List entryList }{
- List: list.getSortedEntries(),
- })
- })
- admin.POST("/post", PostController)
+ //admin.GET("/", server.AdminController)
+ //admin.POST("/post", server.PostController)
//admin.DELETE("/post", DeleteController)
- admin.Static("/static", "admin/static")
+ //admin.Static("/static", "admin/static")
e.Logger.Fatal(e.Start(":40404"))
}
diff --git a/storage/entry.go b/storage/entry.go
new file mode 100644
index 0000000..67371c7
--- /dev/null
+++ b/storage/entry.go
@@ -0,0 +1,71 @@
+package storage
+
+import (
+ "fmt"
+ "strings"
+ "time"
+)
+
+type (
+ JSTime time.Time
+
+ Media struct {
+ Type string `json:"type"`
+ File string `json:"file"`
+ Height int `json:"height"`
+ Width int `json:"width"`
+ }
+
+ Entry struct {
+ Date JSTime `json:"date"`
+ Description string `json:"description"`
+ Post string `json:"post"`
+ Likes int `json:"likes"`
+ Tags []string `json:"tags"`
+ Media []Media `json:"media"`
+ Prev *Entry `json:"-"`
+ Next *Entry `json:"-"`
+ // Users []string
+ }
+)
+
+const (
+ jsTimeLite = "2006-01-02"
+ jsTimeLayout = "2006-01-02 15:04:05"
+ adminUsername = "danolo"
+ adminPassword = "bd4cad796950f50352225de3c773d8f3c39622bc17f34ad661eabe615cdf6d32751c5751e0648dc17d890f40330018334a2ae899878f200f6dc80121ddb70cc9"
+)
+
+// JSTime
+
+func (ct *JSTime) UnmarshalJSON(b []byte) (err error) {
+ s := strings.Trim(string(b), `"`)
+ nt, err := time.Parse(jsTimeLayout, s)
+ *ct = JSTime(nt)
+ return
+}
+
+func (ct JSTime) MarshalJSON() ([]byte, error) {
+ return []byte(ct.String()), nil
+}
+
+func (ct JSTime) String() string {
+ t := time.Time(ct)
+ return fmt.Sprintf("%q", t.Format(jsTimeLayout))
+}
+
+func (ct JSTime) Unix() int64 {
+ return time.Time(ct).Unix()
+}
+
+// Entry
+
+func (entry Entry) Count() map[string]int {
+ count := make(map[string]int)
+ for _, media := range entry.Media {
+ count[media.Type] += 1
+ }
+ return count
+}
+
+func (entry Entry) Len() int { return len(entry.Media) }
diff --git a/storage/list.go b/storage/list.go
new file mode 100644
index 0000000..d4919bf
--- /dev/null
+++ b/storage/list.go
@@ -0,0 +1,167 @@
+package storage
+
+import (
+ "crypto/sha512"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "sort"
+ "sync"
+ "time"
+
+ "github.com/gorilla/feeds"
+ "github.com/labstack/echo"
+)
+
+type (
+ EntryMap struct {
+ Filename string
+ modtime time.Time
+ mapped map[string]*Entry
+ sorted []*Entry
+ mu sync.RWMutex
+ }
+ entryList []*Entry
+)
+
+func (list *EntryMap) Len() int { return len(list.mapped) }
+
+func (list *EntryMap) modified() (mod bool) {
+ info, err := os.Stat(list.Filename)
+ if err == nil {
+ mod = list.modtime.Before(info.ModTime())
+ list.modtime = info.ModTime()
+ } else {
+ mod = true
+ }
+ return
+}
+
+func (list *EntryMap) write() (err error) {
+ data, err := json.MarshalIndent(list.mapped, "", " ")
+ if err == nil {
+ err = ioutil.WriteFile(list.Filename, data, 0644)
+ }
+ return
+}
+
+func (list *EntryMap) read() (err error) {
+ if list.modified() {
+ if data, err := ioutil.ReadFile(list.Filename); err == nil {
+
+ // read map
+ list.mapped = make(map[string]*Entry)
+ err = json.Unmarshal(data, &list.mapped)
+
+ // sort list
+ list.sorted = make([]*Entry, 0, len(list.mapped))
+ for _, entry := range list.mapped {
+ list.sorted = append(list.sorted, entry)
+ }
+ sort.Sort(entryList(list.sorted))
+
+ // assign prev/next
+ for index, value := range list.sorted {
+ if index-1 >= 0 {
+ value.Next = list.sorted[index-1]
+ }
+ if index+1 < len(list.sorted) {
+ value.Prev = list.sorted[index+1]
+ }
+ }
+ }
+ }
+ return
+}
+
+func (list *EntryMap) GetEntries() (result []*Entry, err error) {
+ list.mu.RLock()
+ defer list.mu.RUnlock()
+
+ err = list.read()
+
+ if err == nil {
+ result = list.sorted
+ }
+
+ return
+}
+
+func (list *EntryMap) addEntry(entry *Entry) (err error) {
+ list.mu.Lock()
+ defer list.mu.Unlock()
+
+ list.read()
+
+ if entry != nil {
+ list.mapped[entry.Post] = entry
+ err = list.write()
+ }
+
+ return
+}
+
+func (list *EntryMap) GetEntry(uuid string) (result *Entry, err error) {
+ list.mu.Lock()
+ defer list.mu.Unlock()
+
+ if err = list.read(); err == nil {
+ result = list.mapped[uuid]
+ }
+
+ return
+}
+
+func (list *EntryMap) getFeed() (feed *feeds.Feed) {
+ feed = &feeds.Feed{
+ Title: "danoloan.es igar",
+ Link: &feeds.Link{Href: "https://danoloan.es/igar/"},
+ Description: "bitácora fotográfica de danoloan",
+ Author: &feeds.Author{Name: "danoloan", Email: "danolo@danoloan.es"},
+ }
+
+ feed.Items = make([]*feeds.Item, 0, list.Len())
+
+ elements, err := list.GetEntries()
+ if err != nil {
+ for _, elem := range elements {
+ item := &feeds.Item{
+ Title: elem.Description,
+ Link: &feeds.Link{Href: fmt.Sprintf("https://danoloan.es/igar/view?uuid=%s", elem.Post)},
+ Description: fmt.Sprintf("%s
\n\n", elem.Description),
+ Created: time.Time(elem.Date),
+ }
+
+ for _, media := range elem.Media {
+ if media.Type == "GraphImage" {
+ // TODO ruta relativa al proxy
+ item.Description = fmt.Sprintf("%s\n\t
", item.Description, elem.Post, media.File)
+ }
+ }
+ item.Description = fmt.Sprintf("%s\n
", item.Description)
+
+ feed.Items = append(feed.Items, item)
+ }
+
+ }
+ return
+}
+
+// entryList
+
+func (list entryList) Len() int { return len(list) }
+func (list entryList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
+func (list entryList) Less(i, j int) bool {
+ return time.Time(list[i].Date).After(time.Time(list[j].Date))
+}
+
+func auth(username, password string, c echo.Context) (bool, error) {
+ hash := sha512.Sum512([]byte(password))
+ hashString := hex.EncodeToString(hash[:])
+ if username == adminUsername && hashString == adminPassword {
+ return true, nil
+ }
+ return false, nil
+}
diff --git a/index.html b/templates/index.html
similarity index 56%
rename from index.html
rename to templates/index.html
index 98f19b7..716040c 100644
--- a/index.html
+++ b/templates/index.html
@@ -33,24 +33,19 @@ nav > a {
margin: 5px 0px;
}
-#load {
- text-align: center;
- padding: 20px;
- width: 10em;
-}
-
.elem {
margin: 0px auto;
padding: 5px;
width: calc((100% - 30px) / 3);
max-width: 320px;
+ aspect-ratio: 1/1;
transition: transform .2s;
position: relative;
display: inline-block;
}
.elem:hover {
- transform: scale(1.05);
+ transform: scale(1.025);
z-index: 10;
}
@@ -65,48 +60,39 @@ nav > a {
right: 7%;
}
-img.load {
- width: 50px;
-}
+ @media screen and (max-width: 990px) {
+ body {
+ padding: 0px;
+ }
+ header {
+ padding: 0px 1em;
+ }
+ nav {
+ position: initial;
+ text-align: center;
+ margin-bottom: 1em;
+ }
+ .elem {
+ padding: 1px;
+ width: calc((100% - 6px) / 3);
+ }
+ }
-p {
- margin-top: 0px;
-}
-
- @media screen and (max-width: 990px) {
- body {
- padding: 0px;
+ @media (prefers-color-scheme: light) {
+ nav > a {
+ background-color: #eee;
+ }
+ nav > a:hover {
+ background-color: #ddd;
+ }
}
- header {
- padding: 0px 1em;
- }
- nav {
- position: initial;
- text-align: center;
- margin-bottom: 1em;
- }
- .elem {
- padding: 1px;
- width: calc((100% - 6px) / 3);
- }
- }
-
- @media (prefers-color-scheme: light) {
- nav > a {
- background-color: #eee;
- }
- nav > a:hover {
- background-color: #ddd;
- }
- }
-
-
+
bitácora fotográfica
@@ -122,20 +108,18 @@ p {
Zona del admin 😎
-
+ {{ range . }}
+
+
+ {{ if gt (len .Media) 1 }}
+
+ {{ else if eq (index .Media 0).Type "GraphVideo" }}
+
+ {{ end }}
+
+ {{ end }}
diff --git a/templates/view.html b/templates/view.html
index ea04131..f558cc1 100644
--- a/templates/view.html
+++ b/templates/view.html
@@ -20,7 +20,7 @@ main > img, main > video {
{{if gt .Len 1 }}
max-height: 55vh;
{{ else }}
- max-height: 72vh;
+ max-height: 82vh;
{{ end }}
max-width: 100%;
width: auto;
@@ -90,30 +90,32 @@ document.getElementById("date").innerText =
+ {{ if gt .Len 1 }}
- {{ if .Count.GraphImage }}
-
- {{ .Count.GraphImage }}
-
-
+ {{ if .Count.GraphImage}}
+
+ {{ .Count.GraphImage }}
+
+
{{ end }}
{{ if .Count.GraphVideo }}
-
- {{ .Count.GraphVideo }}
-
-
+
+ {{ .Count.GraphVideo }}
+
+
{{ end }}
+ {{ end }}
{{ $post := .Post }}
@@ -125,6 +127,7 @@ document.getElementById("date").innerText =
{{ end }}
{{ end }}
+ {{ if gt .Len 1 }}
+ {{ end }}