Add /api/images
This commit is contained in:
parent
a12d13aa00
commit
99e09acb56
1
api.go
1
api.go
|
@ -13,6 +13,7 @@ import (
|
|||
type DispatchFunction func(*User, []string, io.ReadCloser) (interface{}, error)
|
||||
|
||||
var apiRoutes = map[string]*(map[string]struct{AuthFunction;DispatchFunction}){
|
||||
"images": &ApiImagesRouting,
|
||||
"version": &ApiVersionRouting,
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
var ApiImagesRouting = map[string]struct{AuthFunction; DispatchFunction}{
|
||||
"GET": {PublicPage, listImages},
|
||||
"POST": {PublicPage, addImage},
|
||||
"DELETE": {PrivatePage, hideImage},
|
||||
}
|
||||
|
||||
func listImages(u *User, args []string, body io.ReadCloser) (interface{}, error) {
|
||||
if len(args) < 1 {
|
||||
return GetPublishedImages()
|
||||
} else if args[0] == "last" {
|
||||
return GetLastImage()
|
||||
} else {
|
||||
return GetPublishedImage(args[0])
|
||||
}
|
||||
}
|
||||
|
||||
func addImage(u *User, args []string, body io.ReadCloser) (interface{}, error) {
|
||||
if len(args) < 1 {
|
||||
return nil, errors.New("Need an image identifier to create")
|
||||
} else if err := AddImage(args[0], body); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func hideImage(u *User, args []string, body io.ReadCloser) (interface{}, error) {
|
||||
if len(args) < 1 {
|
||||
return nil, errors.New("Need an image identifier to delete")
|
||||
} else if pict, err := GetPublishedImage(args[0]); err != nil {
|
||||
return nil, errors.New("No matching image")
|
||||
} else if err := pict.Unpublish(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return true, nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"image"
|
||||
_ "image/gif"
|
||||
"image/jpeg"
|
||||
_ "image/png"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Picture struct {
|
||||
path string
|
||||
basename string
|
||||
Name string `json:"name"`
|
||||
UploadTime time.Time `json:"upload_time"`
|
||||
}
|
||||
|
||||
type ByUploadTime []Picture
|
||||
|
||||
func (a ByUploadTime) Len() int { return len(a) }
|
||||
func (a ByUploadTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a ByUploadTime) Less(i, j int) bool { return a[i].UploadTime.Sub(a[j].UploadTime).Nanoseconds() < 0 }
|
||||
|
||||
func getImages(dir string) ([]Picture, error) {
|
||||
if files, err := ioutil.ReadDir(dir); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
pictures := make([]Picture, 0)
|
||||
for _, file := range files {
|
||||
if !file.IsDir() {
|
||||
filename := file.Name()
|
||||
pictures = append(pictures, Picture{
|
||||
filepath.Join(dir, filename), // Path
|
||||
filename, // Basename
|
||||
filename[:len(filename) - len(filepath.Ext(filename))], // Sanitized filename
|
||||
file.ModTime(), // UploadTime
|
||||
})
|
||||
}
|
||||
}
|
||||
sort.Sort(ByUploadTime(pictures))
|
||||
return pictures, nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetNextImages() ([]Picture, error) {
|
||||
return getImages(NextImgDir)
|
||||
}
|
||||
|
||||
func GetPublishedImages() ([]Picture, error) {
|
||||
return getImages(PublishedImgDir)
|
||||
}
|
||||
|
||||
func GetLastImage() (Picture, error) {
|
||||
if picts, err := GetPublishedImages(); err != nil {
|
||||
return Picture{}, err
|
||||
} else {
|
||||
return picts[len(picts)-1], nil
|
||||
}
|
||||
}
|
||||
|
||||
func getImage(flist func() ([]Picture, error), fname string) (Picture, error) {
|
||||
if picts, err := flist(); err != nil {
|
||||
return Picture{}, err
|
||||
} else if pid, err := strconv.Atoi(fname); err == nil {
|
||||
if pid < len(picts) {
|
||||
return picts[pid], nil
|
||||
} else {
|
||||
return Picture{}, errors.New("Invalid picture identifier")
|
||||
}
|
||||
} else {
|
||||
for _, pict := range picts {
|
||||
if pict.Name == fname || pict.basename == fname {
|
||||
return pict, nil
|
||||
}
|
||||
}
|
||||
return Picture{}, errors.New("No such picture")
|
||||
}
|
||||
}
|
||||
|
||||
func GetPublishedImage(fname string) (Picture, error) {
|
||||
return getImage(GetPublishedImages, fname)
|
||||
}
|
||||
|
||||
func GetNextImage(fname string) (Picture, error) {
|
||||
return getImage(GetNextImages, fname)
|
||||
}
|
||||
|
||||
func UniqueImage(filename string) (bool) {
|
||||
if pict, _ := GetPublishedImage(filename); pict.path != "" {
|
||||
return false
|
||||
} else {
|
||||
if pict, _ := GetNextImage(filename); pict.path != "" {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AddImage(filename string, blob io.ReadCloser) (error) {
|
||||
// Check the name is not already used
|
||||
if ok := UniqueImage(filename); !ok {
|
||||
return errors.New("This filename is already used, please choose another one.")
|
||||
|
||||
// Convert to JPEG
|
||||
} else if img, _, err := image.Decode(blob); err != nil {
|
||||
return err
|
||||
|
||||
// Save file
|
||||
} else if fw, err := os.Create(filepath.Join(NextImgDir, filename + ".jpg")); err != nil {
|
||||
return err
|
||||
} else if err := jpeg.Encode(fw, img, nil); err != nil {
|
||||
return err
|
||||
} else {
|
||||
fw.Close()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p Picture) Publish() (error) {
|
||||
npath := filepath.Join(PublishedImgDir, p.basename)
|
||||
if err := os.Rename(p.path, npath); err != nil {
|
||||
return err
|
||||
} else if err := os.Chtimes(npath, time.Now(), time.Now()); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p Picture) Unpublish() (error) {
|
||||
if err := os.Rename(p.path, filepath.Join(NextImgDir, p.basename)); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p Picture) Remove() (error) {
|
||||
if err := os.Remove(p.path); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue