package server import ( "encoding/json" "errors" "io" "local/dndex/storage/entity" "local/dndex/storage/operator" "log" "net/http" "path" "strings" "gopkg.in/mgo.v2/bson" ) type shortEntity struct { Name string ID string } func (rest *REST) entities(w http.ResponseWriter, r *http.Request) { if scope, err := rest.entityScope(r); err != nil { rest.respNotFound(w) return } else if r.Method != http.MethodGet && len(scope) > 1 { r.Method = http.MethodPatch } switch r.Method { case http.MethodPut: rest.entitiesReplace(w, r) case http.MethodPatch: rest.entitiesUpdate(w, r) case http.MethodPost: rest.entitiesCreate(w, r) case http.MethodGet: rest.entitiesGet(w, r) case http.MethodDelete: rest.entitiesDelete(w, r) default: rest.respNotFound(w) } } func (rest *REST) entitiesCreate(w http.ResponseWriter, r *http.Request) { scope := rest.scope(r) entityScope, _ := rest.entityScope(r) one, err := rest.entityParse(r.Body) if err != nil { rest.respBadRequest(w, err.Error()) return } one.ID = entityScope[0] if err := rest.g.Insert(r.Context(), scope.Namespace, one); err != nil { rest.respError(w, err) return } rest.entitiesGet(w, r) } func (rest *REST) entitiesDelete(w http.ResponseWriter, r *http.Request) { scope := rest.scope(r) if err := rest.g.Delete(r.Context(), scope.Namespace, bson.M{entity.ID: scope.EntityID}); err != nil { rest.respError(w, err) return } rest.respOK(w) } func (rest *REST) entitiesGet(w http.ResponseWriter, r *http.Request) { entityScope, _ := rest.entityScope(r) switch len(entityScope) { case 0: rest.entitiesList(w, r) case 1: rest.entitiesGetOne(w, r) default: rest.entitiesGetOneSub(w, r) } } func (rest *REST) entitiesGetOne(w http.ResponseWriter, r *http.Request) { scope := rest.scope(r) entityScope, _ := rest.entityScope(r) one, err := rest.g.Get(r.Context(), scope.Namespace, entityScope[0]) if err != nil { rest.respNotFound(w) return } rest.respMap(w, entityScope[0], one) } func (rest *REST) entitiesGetOneSub(w http.ResponseWriter, r *http.Request) { entityScope, _ := rest.entityScope(r) scope := rest.scope(r) one, err := rest.g.Get(r.Context(), scope.Namespace, scope.EntityID) if err != nil { rest.respNotFound(w) return } b, err := bson.Marshal(one) if err != nil { rest.respError(w, err) return } var m bson.M err = bson.Unmarshal(b, &m) if err != nil { rest.respError(w, err) return } entityScope = entityScope[1:] for len(entityScope) > 1 { k := entityScope[0] entityScope = entityScope[1:] subm, ok := m[k] if !ok { m = nil break } mm, ok := subm.(bson.M) if !ok { m = nil break } m = mm } rest.respMap(w, scope.EntityID, m[entityScope[0]]) } func (rest *REST) entitiesList(w http.ResponseWriter, r *http.Request) { scope := rest.scope(r) entities, err := rest.g.List(r.Context(), scope.Namespace) if err != nil { rest.respError(w, err) return } short := make([]shortEntity, len(entities)) for i := range entities { short[i] = shortEntity{Name: entities[i].Name, ID: entities[i].ID} } rest.respMap(w, scope.Namespace, short) } func (rest *REST) entitiesReplace(w http.ResponseWriter, r *http.Request) { scope := rest.scope(r) one, err := rest.entityParse(r.Body) if err != nil { rest.respBadRequest(w, err.Error()) return } if one.ID != scope.EntityID && one.ID != "" { rest.respBadRequest(w, "cannot change primary key") return } one.ID = scope.EntityID err = rest.g.Update(r.Context(), scope.Namespace, bson.M{entity.ID: scope.EntityID}, operator.SetMany{Value: one}) if err != nil { rest.respError(w, err) return } rest.entitiesGet(w, r) } func (rest *REST) entitiesUpdate(w http.ResponseWriter, r *http.Request) { log.Println(r.Method) log.Println(rest.entityScope(r)) http.Error(w, "not impl", http.StatusNotImplemented) } func (rest *REST) entityParse(r io.Reader) (entity.One, error) { var one entity.One err := json.NewDecoder(r).Decode(&one) return one, err } func (rest *REST) entityScope(r *http.Request) ([]string, error) { p := r.URL.Path if path.Dir(p) == path.Base(p) { if r.Method == http.MethodGet { return []string{}, nil } return nil, errors.New("nothing specified") } ps := strings.Split(p, "/") ps2 := []string{} for i := range ps { if ps[i] != "" { ps2 = append(ps2, ps[i]) } } return ps2, nil }