package main import ( "encoding/json" "fmt" "html/template" "crypto/sha512" "io" "io/ioutil" "net/http" "os" "os/exec" "sort" "strconv" "strings" "sync" "time" "encoding/hex" "mime" "github.com/labstack/echo" "github.com/labstack/echo/middleware" "github.com/gorilla/feeds" "github.com/google/uuid" //"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), } ) // FUNCTIONS 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) 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) } if err == nil { list.modtime = time.Now() } 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