func (res *resource) handleUpdate(c APIContexter, w http.ResponseWriter, r *http.Request, params map[string]string, info information) error { id := params["id"] obj, err := res.source.FindOne(id, buildRequest(c, r)) if err != nil { return err } ctx, err := unmarshalRequest(r) if err != nil { return err } // we have to make the Result to a pointer to unmarshal into it updatingObj := reflect.ValueOf(obj.Result()) if updatingObj.Kind() == reflect.Struct { updatingObjPtr := reflect.New(reflect.TypeOf(obj.Result())) updatingObjPtr.Elem().Set(updatingObj) err = jsonapi.Unmarshal(ctx, updatingObjPtr.Interface()) updatingObj = updatingObjPtr.Elem() } else { err = jsonapi.Unmarshal(ctx, updatingObj.Interface()) } if err != nil { return NewHTTPError(nil, err.Error(), http.StatusNotAcceptable) } response, err := res.source.Update(updatingObj.Interface(), buildRequest(c, r)) if err != nil { return err } switch response.StatusCode() { case http.StatusOK: updated := response.Result() if updated == nil { internalResponse, err := res.source.FindOne(id, buildRequest(c, r)) if err != nil { return err } updated = internalResponse.Result() if updated == nil { return fmt.Errorf("Expected FindOne to return one object of resource %s", res.name) } response = internalResponse } return res.respondWith(response, info, http.StatusOK, w, r) case http.StatusAccepted: w.WriteHeader(http.StatusAccepted) return nil case http.StatusNoContent: w.WriteHeader(http.StatusNoContent) return nil default: return fmt.Errorf("invalid status code %d from resource %s for method Update", response.StatusCode(), res.name) } }
func (res *resource) handleCreate(c APIContexter, w http.ResponseWriter, r *http.Request, prefix string, info information) error { ctx, err := unmarshalRequest(r) if err != nil { return err } // Ok this is weird again, but reflect.New produces a pointer, so we need the pure type without pointer, // otherwise we would have a pointer pointer type that we don't want. resourceType := res.resourceType if resourceType.Kind() == reflect.Ptr { resourceType = resourceType.Elem() } newObj := reflect.New(resourceType).Interface() err = jsonapi.Unmarshal(ctx, newObj) if err != nil { return err } var response Responder if res.resourceType.Kind() == reflect.Struct { // we have to dereference the pointer if user wants to use non pointer values response, err = res.source.Create(reflect.ValueOf(newObj).Elem().Interface(), buildRequest(c, r)) } else { response, err = res.source.Create(newObj, buildRequest(c, r)) } if err != nil { return err } result, ok := response.Result().(jsonapi.MarshalIdentifier) if !ok { return fmt.Errorf("Expected one newly created object by resource %s", res.name) } if len(prefix) > 0 { w.Header().Set("Location", "/"+prefix+"/"+res.name+"/"+result.GetID()) } else { w.Header().Set("Location", "/"+res.name+"/"+result.GetID()) } // handle 200 status codes switch response.StatusCode() { case http.StatusCreated: return res.respondWith(response, info, http.StatusCreated, w, r) case http.StatusNoContent: w.WriteHeader(response.StatusCode()) return nil case http.StatusAccepted: w.WriteHeader(response.StatusCode()) return nil default: return fmt.Errorf("invalid status code %d from resource %s for method Create", response.StatusCode(), res.name) } }
func ParseJSONBody(c *echo.Context, dest interface{}) error { body, err := ioutil.ReadAll(c.Request().Body) if err != nil { return errors.InvalidRequest } err = jsonapi.Unmarshal(body, dest) if err != nil { return errors.InvalidRequest } return nil }
// DeviceTokenCreate will create a deviceToken for a specified user // @parameters // @requires deviceType // @requires token // @returns the newly created deviceToken func DeviceTokenCreate(c *gin.Context) { var dt models.DeviceToken buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &dt) if err2 != nil { parseFail := appError.JSONParseFailure parseFail.Detail = err2.Error() c.AbortWithError(http.StatusMethodNotAllowed, err2). SetMeta(parseFail) return } dt.UserID = c.Keys["CurrentUserID"].(uint) // Validate our new deviceToken isValid, errApp := dt.Validate() if isValid == false { c.AbortWithError(errApp.Status, errApp). SetMeta(errApp) return } var existingDeviceToken models.DeviceToken // If deviceToken is not found, then create the token // else update the existing device token with the new one if database.DBCon.Where("user_id = ?", dt.UserID).First(&existingDeviceToken).RecordNotFound() { database.DBCon.Create(&dt) } else { database.DBCon.Model(&existingDeviceToken).Update("token", dt.Token) dt = existingDeviceToken } data, err := jsonapi.Marshal(&dt) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusCreated, "application/vnd.api+json", data) }
// UnmarshalJSON sets *as to a copy of data. func (as *AppSet) UnmarshalJSON(bytes []byte) error { var ( appBytes []byte containerBytes []byte err error data TmpJSON ) if err = json.Unmarshal(bytes, &data); err != nil { return err } apps := SelectResources(data, "apps") containers := SelectResources(data, "containers") if appBytes, err = json.Marshal(apps); err != nil { return err } if containerBytes, err = json.Marshal(containers); err != nil { return err } var parsedApps []App if err = jsonapi.Unmarshal(appBytes, &parsedApps); err != nil { return err } var parsedContainers []Container if err = jsonapi.Unmarshal(containerBytes, &parsedContainers); err != nil { return err } as.App = parsedApps[0] as.Container = parsedContainers[0] return nil }
// TransactionCreate will create a transaction that occurs // between two users in a group // @parameters // @requires type // @requires amount // @requires relatedObjectId // @requires relatedObjectType // @requires recipientId // @requires senderid // @optional memo // @returns the newly created transaction func TransactionCreate(c *gin.Context) { var t models.Transaction buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &t) if err2 != nil { parseFail := appError.JSONParseFailure parseFail.Detail = err2.Error() c.AbortWithError(http.StatusMethodNotAllowed, err2). SetMeta(parseFail) return } t.CreatorID = c.Keys["CurrentUserID"].(uint) // Validate our new transaction isValid, errApp := t.Validate() if isValid == false { c.AbortWithError(errApp.Status, errApp). SetMeta(errApp) return } database.DBCon.Create(&t) database.DBCon.First(&t.Recipient, t.RecipientID) database.DBCon.First(&t.Sender, t.SenderID) database.DBCon.First(&t.Creator, t.CreatorID) data, err := jsonapi.Marshal(&t) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusCreated, "application/vnd.api+json", data) }
// GroupUpdate is used to update a specific group, it'll also come with some form data' // @returns a group struct func GroupUpdate(c *gin.Context) { var group models.Group buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &group) if err2 != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } // Little hack-ish // Remove all current relations database.DBCon.Exec("DELETE FROM group_users WHERE group_id = ?", group.ID) // Add all the given relations for _, c := range group.UserIDs { database.DBCon. Exec("INSERT INTO group_users (group_id, user_id) VALUES (?, ?)", group.ID, c) } database.DBCon.First(&group, group.ID) database.DBCon.Model(&group).Related(&group.Users, "Users") data, err := jsonapi.Marshal(group) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// GroupCreate is used to create one specific group, it'll come with some form data // @returns a group struct func GroupCreate(c *gin.Context) { var group models.Group buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &group) if err2 != nil { parseFail := appError.JSONParseFailure parseFail.Detail = err2.Error() c.AbortWithError(http.StatusMethodNotAllowed, err2). SetMeta(parseFail) return } database.DBCon.Create(&group) // Add current user to the group database.DBCon. Exec("INSERT INTO group_users (group_id, user_id) VALUES (?, ?)", group.ID, c.Keys["CurrentUserID"].(uint)) database.DBCon.Model(&group).Related(&group.Users, "Users") data, err3 := jsonapi.Marshal(&group) if err3 != nil { c.AbortWithError(http.StatusInternalServerError, err3). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusCreated, "application/vnd.api+json", data) }
// TransactionUpdate will update an existing transaction // between two users in a group // @parameters // @requires id // @optional type // @optional recipientId // @optional senderId // @optional amount // @optional memo // @returns the updated transaction func TransactionUpdate(c *gin.Context) { var t models.Transaction var newT models.Transaction if database.DBCon.First(&t, c.Param("id")).RecordNotFound() { c.AbortWithError(http.StatusNotFound, appError.RecordNotFound). SetMeta(appError.RecordNotFound) return } // Ensure current user is creator of transaction if t.CreatorID != c.Keys["CurrentUserID"].(uint) { c.AbortWithError(appError.InsufficientPermission.Status, appError.InsufficientPermission). SetMeta(appError.InsufficientPermission) return } buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &newT) if err2 != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } t.Type = newT.Type t.Amount = newT.Amount t.Memo = newT.Memo t.RecipientID = newT.RecipientID t.SenderID = newT.SenderID // Validate our new transaction isValid, errApp := t.Validate() if isValid == false { c.AbortWithError(errApp.Status, errApp). SetMeta(errApp) return } database.DBCon.Save(&t) database.DBCon.First(&t.Recipient, t.RecipientID) database.DBCon.First(&t.Sender, t.SenderID) database.DBCon.First(&t.Creator, t.CreatorID) data, err := jsonapi.Marshal(&t) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }