Refactor de subidas y eliminaciones
This commit is contained in:
parent
b110cdcacc
commit
b37dd824de
62
main.go
62
main.go
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"html/template"
|
||||
"igar/storage"
|
||||
"io"
|
||||
|
@ -9,6 +11,7 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
//"github.com/labstack/echo/middleware"
|
||||
)
|
||||
|
||||
|
@ -56,6 +59,53 @@ func ViewController(c echo.Context) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func AdminController(c echo.Context) (err error) {
|
||||
entries, err := list.GetEntries()
|
||||
if err == nil {
|
||||
err = c.Render(http.StatusOK, "admin.html", entries)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func PostController(c echo.Context) (err error) {
|
||||
desc := c.FormValue("desc")
|
||||
date := c.FormValue("date")
|
||||
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
entry := storage.NewEntry(desc, date)
|
||||
entry.GeneratePostID()
|
||||
entry.AddMedia(file)
|
||||
|
||||
list.AddEntry(entry)
|
||||
|
||||
return c.String(http.StatusCreated, "")
|
||||
}
|
||||
|
||||
func DeleteController(c echo.Context) (err error) {
|
||||
uuid := c.QueryParam("uuid")
|
||||
entry := list.RemoveEntry(uuid)
|
||||
entry.RemoveFiles()
|
||||
if entry == nil {
|
||||
return c.String(http.StatusNotFound, "")
|
||||
}
|
||||
return c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
func auth(username, password string, c echo.Context) (bool, error) {
|
||||
adminUsername := "danolo"
|
||||
adminPassword := "bd4cad796950f50352225de3c773d8f3c39622bc17f34ad661eabe615cdf6d32751c5751e0648dc17d890f40330018334a2ae899878f200f6dc80121ddb70cc9"
|
||||
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()
|
||||
|
||||
|
@ -66,8 +116,6 @@ func main() {
|
|||
e.GET("/", IndexController)
|
||||
e.GET("/view", ViewController)
|
||||
|
||||
//e.GET("/list", server.ListController)
|
||||
|
||||
//e.GET("/rss", server.RSSController)
|
||||
//e.GET("/json", server.JSONController)
|
||||
//e.GET("/atom", server.AtomController)
|
||||
|
@ -75,13 +123,13 @@ func main() {
|
|||
e.Static("/static", "static")
|
||||
e.Static("/img", "/var/lib/igar")
|
||||
|
||||
//admin := e.Group("/admin", middleware.BasicAuth(auth))
|
||||
admin := e.Group("/admin", middleware.BasicAuth(auth))
|
||||
|
||||
//admin.GET("/", server.AdminController)
|
||||
//admin.POST("/post", server.PostController)
|
||||
//admin.DELETE("/post", DeleteController)
|
||||
admin.GET("/", AdminController)
|
||||
admin.POST("/post", PostController)
|
||||
admin.DELETE("/post", DeleteController)
|
||||
|
||||
//admin.Static("/static", "admin/static")
|
||||
admin.Static("/static", "admin/static")
|
||||
|
||||
e.Logger.Fatal(e.Start(":40404"))
|
||||
}
|
||||
|
|
121
storage/entry.go
121
storage/entry.go
|
@ -2,20 +2,18 @@ package storage
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
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"`
|
||||
|
@ -29,37 +27,6 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
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 {
|
||||
|
@ -69,3 +36,77 @@ func (entry Entry) Count() map[string]int {
|
|||
}
|
||||
|
||||
func (entry Entry) Len() int { return len(entry.Media) }
|
||||
|
||||
func (entry *Entry) GeneratePostID() {
|
||||
entry.Post = strings.Replace(uuid.New().String(), "-", "", -1)
|
||||
}
|
||||
|
||||
func (entry *Entry) AddMedia(file *multipart.FileHeader) (err error) {
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
name := strings.Replace(uuid.New().String(), "-", "", -1)
|
||||
extension, err := mime.ExtensionsByType(file.Header.Get("Content-Type"))
|
||||
if err == nil {
|
||||
name = fmt.Sprintf("%s%s", name, extension[0])
|
||||
}
|
||||
|
||||
media := Media{
|
||||
Type: "GraphImage",
|
||||
File: name,
|
||||
}
|
||||
|
||||
// TODO ruta relativa
|
||||
postdir := fmt.Sprintf("/var/lib/igar/%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()
|
||||
|
||||
if _, err = io.Copy(dst, src); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = exec.Command("node", "thumbs/make_thumb.js", postdir).Run(); err != nil {
|
||||
// TODO fichero copiado no usado (limpieza?)
|
||||
return
|
||||
}
|
||||
|
||||
entry.Media = append(entry.Media, media)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (entry *Entry) RemoveFiles() error {
|
||||
// Beware of removing the root directory!
|
||||
if entry.Post != "" {
|
||||
path := fmt.Sprintf("/var/lib/igar/%s", entry.Post)
|
||||
return os.RemoveAll(path)
|
||||
}
|
||||
// TODO return nil if not found?
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewEntry(desc string, date string) (entry *Entry) {
|
||||
var entryTime time.Time
|
||||
|
||||
if date != "" {
|
||||
entryTime, _ = time.Parse(jsTimeLite, date)
|
||||
} else {
|
||||
entryTime = time.Now()
|
||||
}
|
||||
|
||||
entry = &Entry{
|
||||
Description: desc,
|
||||
Date: JSTime(entryTime),
|
||||
}
|
||||
entry.GeneratePostID()
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -12,7 +10,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gorilla/feeds"
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -26,7 +23,13 @@ type (
|
|||
entryList []*Entry
|
||||
)
|
||||
|
||||
func (list *EntryMap) Len() int { return len(list.mapped) }
|
||||
// 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 (list *EntryMap) modified() (mod bool) {
|
||||
info, err := os.Stat(list.Filename)
|
||||
|
@ -76,45 +79,34 @@ func (list *EntryMap) read() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (list *EntryMap) GetEntries() (result []*Entry, err error) {
|
||||
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) GetEntries() (result []Entry, err error) {
|
||||
list.mu.RLock()
|
||||
defer list.mu.RUnlock()
|
||||
|
||||
err = list.read()
|
||||
|
||||
if err == nil {
|
||||
result = list.sorted
|
||||
result = make([]Entry, len(list.sorted))
|
||||
for index, elem := range list.sorted {
|
||||
result[index] = *elem
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
func (list *EntryMap) GetFeed() (feed *feeds.Feed) {
|
||||
feed = &feeds.Feed{
|
||||
Title: "danoloan.es igar",
|
||||
Link: &feeds.Link{Href: "https://danoloan.es/igar/"},
|
||||
|
@ -149,19 +141,34 @@ func (list *EntryMap) getFeed() (feed *feeds.Feed) {
|
|||
return
|
||||
}
|
||||
|
||||
// entryList
|
||||
func (list *EntryMap) Len() int { return len(list.mapped) }
|
||||
|
||||
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 (list *EntryMap) AddEntry(entry *Entry) (err error) {
|
||||
list.mu.Lock()
|
||||
defer list.mu.Unlock()
|
||||
|
||||
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
|
||||
list.read()
|
||||
|
||||
if entry != nil {
|
||||
list.mapped[entry.Post] = entry
|
||||
err = list.write()
|
||||
}
|
||||
return false, nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (list *EntryMap) RemoveEntry(uuid string) (entry *Entry) {
|
||||
list.mu.Lock()
|
||||
defer list.mu.Unlock()
|
||||
|
||||
list.read()
|
||||
|
||||
entry, ok := list.mapped[uuid]
|
||||
if ok {
|
||||
delete(list.mapped, uuid)
|
||||
}
|
||||
|
||||
list.write()
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
JSTime time.Time
|
||||
)
|
||||
|
||||
const (
|
||||
jsTimeLite = "2006-01-02"
|
||||
jsTimeLayout = "2006-01-02 15:04:05"
|
||||
)
|
||||
|
||||
func (ct *JSTime) UnmarshalJSON(b []byte) (err error) {
|
||||
s := strings.Trim(string(b), `"`)
|
||||
loc, _ := time.LoadLocation("Europe/Madrid")
|
||||
nt, err := time.ParseInLocation(jsTimeLayout, s, loc)
|
||||
*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()
|
||||
}
|
||||
|
||||
func (ct JSTime) Local() JSTime {
|
||||
return JSTime(time.Time(ct).Local())
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package storage
|
||||
|
||||
type (
|
||||
Media struct {
|
||||
Type string `json:"type"`
|
||||
File string `json:"file"`
|
||||
Height int `json:"height"`
|
||||
Width int `json:"width"`
|
||||
}
|
||||
)
|
|
@ -24,7 +24,7 @@
|
|||
<button class="cajetin">Archivar/Eliminar imagen</button>
|
||||
<div class="action list">
|
||||
<div class="scroll" id="dellist">
|
||||
{{ range .List }}
|
||||
{{ range . }}
|
||||
<div class="action">
|
||||
<div class="date"> {{ .Date }} </div>
|
||||
<div class="desc"> {{ .Description }} </div>
|
||||
|
@ -68,7 +68,7 @@ function open(uuid) {
|
|||
|
||||
async function archive(uuid) {
|
||||
if (confirm('Vas a archivar una imagen. ¿Estás seguro?')) {
|
||||
response = await fetch(`post/${uuid}`, { method: 'DELETE' })
|
||||
response = await fetch(`post?uuid=${uuid}`, { method: 'DELETE' })
|
||||
if (response.ok) {
|
||||
remove(this);
|
||||
result(this, 'Imagen archivada');
|
||||
|
@ -81,7 +81,7 @@ async function archive(uuid) {
|
|||
|
||||
async function delpost(uuid) {
|
||||
if (confirm('Vas a eliminar una imagen. ¿Estás seguro?')) {
|
||||
response = await fetch(`post/${uuid}?purge=true`, { method: 'DELETE' });
|
||||
response = await fetch(`post?uuid=${uuid}&purge=true`, { method: 'DELETE' });
|
||||
if (response.ok) {
|
||||
remove(this);
|
||||
result(this, 'Imagen eliminada');
|
||||
|
@ -141,7 +141,7 @@ form.onsubmit = function(event) {
|
|||
xhr.open('POST', 'post', true);
|
||||
|
||||
xhr.upload.onprogress = (prog) => {
|
||||
result(form, `${prog.loaded / prog.total * 100}%`);
|
||||
result(form, `${Math.round(prog.loaded * 100.0 / prog.total)}%`);
|
||||
}
|
||||
|
||||
// Set up a handler for when the task for the request is complete
|
||||
|
|
|
@ -75,7 +75,7 @@ span.count {
|
|||
{{ .Description }}
|
||||
</div>
|
||||
<div id="date">
|
||||
{{ .Date.String }}
|
||||
{{ .Date }}
|
||||
</div>
|
||||
<script>
|
||||
;
|
||||
|
|
Loading…
Reference in New Issue