package view import ( "encoding/json" "errors" "io/ioutil" "local/dndex/storage" "local/dndex/storage/entity" "local/dndex/storage/operator" "net/http" "path" "strings" "github.com/buger/jsonparser" "go.mongodb.org/mongo-driver/bson" ) func who(g storage.Graph, w http.ResponseWriter, r *http.Request) error { namespace := strings.TrimLeft(r.URL.Path, path.Dir(r.URL.Path)) if len(namespace) == 0 { http.NotFound(w, r) return nil } namespace = strings.Replace(namespace, "/", ".", -1) switch r.Method { case http.MethodGet: return whoGet(namespace, g, w, r) case http.MethodPut: return whoPut(namespace, g, w, r) case http.MethodPost: return whoPost(namespace, g, w, r) case http.MethodDelete: return whoDelete(namespace, g, w, r) case http.MethodPatch: return whoPatch(namespace, g, w, r) case http.MethodTrace: return whoTrace(namespace, g, w, r) default: http.NotFound(w, r) return nil } } func whoGet(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { id := r.URL.Query().Get("id") if id == "" { http.Error(w, `{"error":"no ?id provided"}`, http.StatusBadRequest) return nil } _, light := r.URL.Query()["light"] ones, err := g.List(r.Context(), namespace, id) if err != nil { return err } if len(ones) == 0 { http.NotFound(w, r) return nil } if len(ones) > 1 { return errors.New("more than one result found matching " + id) } one := ones[0] if !light && len(one.Connections) > 0 { ones, err := g.List(r.Context(), namespace, one.Peers()...) if err != nil { return err } for _, another := range ones { another.Relationship = one.Connections[another.Name].Relationship one.Connections[another.Name] = another } } enc := json.NewEncoder(w) enc.SetIndent("", " ") return enc.Encode(one) } func whoPut(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { id := r.URL.Query().Get("id") if id == "" { http.Error(w, `{"error":"no ?id provided"}`, http.StatusBadRequest) return nil } body, err := ioutil.ReadAll(r.Body) if err != nil { return err } operation := entity.One{} if err := json.Unmarshal(body, &operation); err != nil { return err } if operation.Name != "" && operation.Name != id { http.Error(w, `{"error":"names differ between URL and request body"}`, http.StatusBadRequest) return nil } if operation.Modified != 0 { http.Error(w, `{"error":"cannot specify modified in request body"}`, http.StatusBadRequest) return nil } b, err := bson.Marshal(operation) if err != nil { return err } op := bson.M{} if err := bson.Unmarshal(b, &op); err != nil { return err } for k := range op { if _, _, _, err := jsonparser.Get(body, k); err != nil { delete(op, k) } } if err := g.Update(r.Context(), namespace, entity.One{Name: id}, operator.SetMany{Value: op}); err != nil { return err } return whoGet(namespace, g, w, r) } func whoPost(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { id := r.URL.Query().Get("id") if id == "" { http.Error(w, `{"error":"no ?id provided"}`, http.StatusBadRequest) return nil } one := entity.One{} if err := json.NewDecoder(r.Body).Decode(&one); err != nil { return err } one.Name = id if err := g.Insert(r.Context(), namespace, one); err != nil { return err } return whoGet(namespace, g, w, r) } func whoDelete(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { id := r.URL.Query().Get("id") if id == "" { http.Error(w, `{"error":"no ?id provided"}`, http.StatusBadRequest) return nil } if err := g.Delete(r.Context(), namespace, entity.One{Name: id}); err != nil { return err } return json.NewEncoder(w).Encode(`{"status":"ok"}`) } func whoPatch(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { id := r.URL.Query().Get("id") if id == "" { http.Error(w, `{"error":"no ?id provided"}`, http.StatusBadRequest) return nil } one := entity.One{} if err := json.NewDecoder(r.Body).Decode(&one); err != nil { return err } if one.Name == "" { http.Error(w, `{"error":"no name provided"}`, http.StatusBadRequest) return nil } relationship := one.Relationship one.Relationship = "" if err := g.Insert(r.Context(), namespace, one); err != nil { return err } one.Relationship = relationship if err := g.Update(r.Context(), namespace, entity.One{Name: id}, operator.Set{Key: "connections." + one.Name, Value: one.Peer()}); err != nil { return err } return whoGet(namespace, g, w, r) } func whoTrace(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { ones, err := g.List(r.Context(), namespace) if err != nil { return err } names := make([]string, len(ones)) for i := range ones { names[i] = ones[i].Name } enc := json.NewEncoder(w) enc.SetIndent("", " ") return enc.Encode(names) }