func locationUpdate(db data.DB, u *models.User, e *models.Event) { loc, _ := e.Location(db) p, err := user.Profile(db, u) if err == data.ErrNotFound { p = models.NewProfile() p.CreatedAt = time.Now() p.UpdatedAt = p.CreatedAt p.SetID(db.NewID()) p.SetOwner(u) } p.SetLocation(loc) db.Save(p) }
// EventPOST implements gaia's response to a POST request to the '/event/' endpoint. // // Assumptions: The user has been authenticated. // // Proceedings: Parses the url parameters. func EventPOST(ctx context.Context, w http.ResponseWriter, r *http.Request, db data.DB, logger services.Logger) { l := logger.WithPrefix("EventPOST: ") // Parse the form if err := r.ParseForm(); err != nil { l.Printf("error parsing form: %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } // Retrieve the tags parameter tagNames, ok := r.Form[tagsParam] if !ok { l.Print("no tags param") tagNames = []string{} } // if any tag names have commas, split those tagNames = flatten(mapSplit(tagNames, ",")) // Retrieve our user u, ok := user.FromContext(ctx) if !ok { l.Print("failed to retrieve user from context") http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } e := new(models.Event) tags := make([]*models.Tag, len(tagNames)) for i, n := range tagNames { t, err := tag.ForName(db, u, tag.Name(n)) if err != nil { l.Printf("tag.ForName(%q) error: %s", n, err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } tags[i] = t } defer r.Body.Close() if requestBody, err := ioutil.ReadAll(r.Body); err != nil { l.Printf("ioutil.ReadAll(r.Body) error: %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } else if err := json.Unmarshal(requestBody, e); err != nil { l.Printf("info: request body:\n%s", string(requestBody)) l.Printf("error: while unmarshalling request body, %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } if e.CreatedAt.IsZero() { e.CreatedAt = time.Now() } e.UpdatedAt = time.Now() e.SetOwner(u) for _, t := range tags { e.IncludeTag(t) } if allowed, err := access.CanCreate(db, u, e); err != nil { l.Printf("access.CanCreate(db, u, e) error: %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } else if !allowed { l.Print("access.CanCreate(db, u, e) rejected authorization") http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return } if err := db.Save(u); err != nil { l.Printf("error saving record: %s", err) switch err { case data.ErrAccessDenial: http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) // These are all equally distressing case data.ErrNotFound: // TODO shouldn't a not found not be fing impossible for a Save? fallthrough case data.ErrNoConnection: fallthrough case data.ErrInvalidID: default: http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } return } // Now we shall write our response b, err := json.MarshalIndent(e, "", " ") if err != nil { l.Printf("json.MarshalIndent(m, \"\", \" \") error: %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } w.WriteHeader(http.StatusCreated) w.Header().Set("Content-Type", "application/json") w.Write(b) }
func TestRecordsEditGET(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx, ok := Authenticate(ctx, w, r, logger, db) if !ok { t.Fatal("authentication failed") } Records.EditGET(ctx, w, r, db, logger) })) defer s.Close() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatal(err) } e := new(models.Event) e.SetID(db.NewID()) e.SetOwner(u) e.Name = "eventname" if err := db.Save(e); err != nil { t.Fatal("db.Save(e) error: %s", err) } c := new(http.Client) req, err := http.NewRequest("GET", s.URL+"?"+url.Values{ "kind": []string{string(models.EventKind)}, "id": []string{e.Id}, }.Encode(), nil) if err != nil { t.Fatal(err) } req.SetBasicAuth("username", "password") resp, err := c.Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } t.Logf("Body:\n%s", body) doc := string(body) contains := map[string]bool{ "eventname": true, "name": true, } for c, want := range contains { if got := strings.Contains(doc, c); got != want { t.Fatalf("strings.Contains(%q): got %t, want %t", c, got, want) } } }
// TestEventPOST tests a POST request to the '/event/' endpoint. // in the happy case (i.e., all parameters present). // We verify: // * The event's name // * The event's data // * The event's tags func TestEventPOST(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx, ok := routes.Authenticate(ctx, w, r, logger, db) if !ok { t.Error("routes.Authenticate failed") } routes.EventPOST(ctx, w, r, db, logger) })) defer s.Close() _, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create(db, \"username\", \"password\") error: %s", err) } u := s.URL + "?" + url.Values{ "tags": []string{"tag1", "tag2"}, }.Encode() body := map[string]interface{}{ "name": "event name", "time": time.Now(), "data": map[string]interface{}{ "arbitrary": []string{"data"}, "here": 1.0, "foo": map[string]interface{}{ "bar": "there", }, }, } b, err := json.Marshal(body) if err != nil { t.Fatal("json.Marshal(body) error: %s", err) } req, err := http.NewRequest("POST", u, bytes.NewBuffer(b)) req.SetBasicAuth("username", "password") client := new(http.Client) resp, err := client.Do(req) if err != nil { t.Fatalf("client.Do(req) error: %s", err) } defer resp.Body.Close() if got, want := resp.StatusCode, http.StatusCreated; got != want { t.Fatalf("resp.StatusCode: got %d, want %d", got, want) } b, err = ioutil.ReadAll(resp.Body) if err != nil { t.Fatalf("ioutil.ReadAll(resp.Body) error: %s", err) } e := new(models.Event) if err := json.Unmarshal(b, e); err != nil { t.Fatalf("json.Unmarshal(b, e) error: %s", err) } t.Logf("Event:\n\t%v", e) if got, want := e.Name, "event name"; got != want { t.Errorf("e.Name: got %q, want %q", got, want) } if got, want := e.Data["foo"].(map[string]interface{})["bar"], "there"; got != want { t.Errorf("e.Data[\"foo\"][\"bar\"]: got %q, want %q", got, want) } if got, want := len(e.TagsIds), 2; got != want { t.Fatalf("len(e.TagsIds): got %d, want %d", got, want) } tags, err := e.Tags(db) if err != nil { t.Fatalf("e.Tags(db) error: %s", err) } if got, want := len(tags), 2; got != want { t.Fatalf("len(tags): got %d, want %d", got, want) } if got, want := tags[0].Name, "tag1"; got != want { t.Errorf("tags[0].Name: got %q, want %q", got, want) } if got, want := tags[1].Name, "tag2"; got != want { t.Errorf("tags[1].Name: got %q, want %q", got, want) } }