photostorate -> minio/importer
diff --git a/apps/minio/importer/cmd/main.go b/apps/minio/importer/cmd/main.go
new file mode 100644
index 0000000..5d381dc
--- /dev/null
+++ b/apps/minio/importer/cmd/main.go
@@ -0,0 +1,19 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "net/http"
+
+ "github.com/giolekva/pcloud/apps/minio/importer"
+)
+
+var port = flag.Int("port", 123, "Port to listen on.")
+var apiAddr = flag.String("api_addr", "http://localhost/graphql", "PCloud GraphQL API server address.")
+
+func main() {
+ flag.Parse()
+ http.Handle("/new_object", &importer.Handler{*apiAddr})
+ log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
+}
diff --git a/apps/minio/importer/importer.go b/apps/minio/importer/importer.go
new file mode 100644
index 0000000..38e0637
--- /dev/null
+++ b/apps/minio/importer/importer.go
@@ -0,0 +1,89 @@
+package importer
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+
+ "github.com/golang/glog"
+ "github.com/itaysk/regogo"
+)
+
+var jsonContentType = "application/json"
+
+var addImgTmpl = `mutation {
+ addImage(input: [{ objectPath: %s }]) {
+ image {
+ id
+ }
+ }
+}`
+
+type Query struct {
+ Query string
+}
+
+func EventToQuery(event string) (Query, error) {
+ key, err := regogo.Get(event, "input.Key")
+ if err != nil {
+ return Query{}, err
+ }
+ keyStr := key.String()
+ if keyStr == "" {
+ return Query{}, errors.New("Key not found")
+ }
+ objectPath, err := json.Marshal(key.String())
+ if err != nil {
+ return Query{}, err
+ }
+ return Query{fmt.Sprintf(addImgTmpl, objectPath)}, nil
+}
+
+type Handler struct {
+ ApiAddr string
+}
+
+func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ body, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ glog.Error(err)
+ http.Error(w, "Could not read HTTP request body", http.StatusBadRequest)
+ return
+ }
+ if len(body) == 0 {
+ // Just a health check from Minio
+ return
+ }
+ bodyStr := string(body)
+ glog.Infof("Received event from Minio: %s", bodyStr)
+ query, err := EventToQuery(bodyStr)
+ if err != nil {
+ glog.Error(err)
+ http.Error(w, "INTERNAL", http.StatusBadRequest)
+ return
+ }
+ glog.Info(query)
+ queryJson, err := json.Marshal(query)
+ if err != nil {
+ panic(err)
+ }
+ resp, err := http.Post(h.ApiAddr, jsonContentType, bytes.NewReader(queryJson))
+ if err != nil {
+ glog.Error(err)
+ http.Error(w, "Query failed", http.StatusInternalServerError)
+ return
+ }
+ if resp.StatusCode != http.StatusOK {
+ glog.Error(resp.StatusCode)
+ http.Error(w, "Query failed", resp.StatusCode)
+ return
+ }
+ respBody, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ panic(err)
+ }
+ glog.Info(string(respBody))
+}
diff --git a/apps/minio/importer/importer_test.go b/apps/minio/importer/importer_test.go
new file mode 100644
index 0000000..90fad07
--- /dev/null
+++ b/apps/minio/importer/importer_test.go
@@ -0,0 +1,116 @@
+package importer
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+func checkErr(err error, t *testing.T) {
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+type OkHandler struct {
+}
+
+func (h *OkHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+
+}
+
+type ErrorHandler struct {
+}
+
+func (h *ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ http.Error(w, "", http.StatusBadRequest)
+}
+
+func TestValidEvent(t *testing.T) {
+ q, err := EventToQuery(`{"Key": "foo/bar"}`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected := `mutation {
+ addImage(input: [{ objectPath: "foo/bar" }]) {
+ image {
+ id
+ }
+ }
+}`
+ if q.Query != expected {
+ t.Fatal(q.Query)
+ }
+}
+
+func TestValidEventEscaping(t *testing.T) {
+ q, err := EventToQuery(`{"Key": "foo\"bar"}`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected := `mutation {
+ addImage(input: [{ objectPath: "foo\"bar" }]) {
+ image {
+ id
+ }
+ }
+}`
+ if q.Query != expected {
+ t.Fatal(q.Query)
+ }
+}
+
+func TestNoKey(t *testing.T) {
+ _, err := EventToQuery(`{"foo": "bar"}`)
+ if err == nil {
+ t.Fatal("Got key")
+ }
+}
+
+func TestInvalidKey(t *testing.T) {
+ _, err := EventToQuery(`{"foo": 123}`)
+ if err == nil {
+ t.Fatal("Got key")
+ }
+}
+
+func TestInvalidKeyComplex(t *testing.T) {
+ _, err := EventToQuery(`{"foo": {"bar": 5}}`)
+ if err == nil {
+ t.Fatal("Got key")
+ }
+}
+
+func TestHandlerOk(t *testing.T) {
+ mockApi := httptest.NewServer(&OkHandler{})
+ r, err := http.NewRequest("GET", "/foo", strings.NewReader(`{"Key": "foo/bar"}`))
+ checkErr(err, t)
+ rec := httptest.NewRecorder()
+ (&Handler{mockApi.URL}).ServeHTTP(rec, r)
+ if rec.Code != http.StatusOK {
+ t.Fatal(rec.Code)
+ }
+}
+
+func TestHandlerInvalidEvent(t *testing.T) {
+ mockApi := httptest.NewServer(&OkHandler{})
+ r, err := http.NewRequest("GET", "/foo", strings.NewReader(`{"Key": 123}`))
+ checkErr(err, t)
+ rec := httptest.NewRecorder()
+ (&Handler{mockApi.URL}).ServeHTTP(rec, r)
+ if rec.Code != http.StatusBadRequest {
+ t.Fatal(rec.Code)
+ }
+}
+
+func TestHandlerError(t *testing.T) {
+ mockApi := httptest.NewServer(&ErrorHandler{})
+ r, err := http.NewRequest("GET", "/foo", strings.NewReader(`{"Key": "foo/bar"}`))
+ checkErr(err, t)
+ rec := httptest.NewRecorder()
+ (&Handler{mockApi.URL}).ServeHTTP(rec, r)
+ if rec.Code == http.StatusOK {
+ t.Fatal(rec.Code)
+ }
+}