func saveBlocks(params martini.Params, w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) keyIDStr := params["key"] if keyIDStr == "" { handleError(c, w, errors.New("the pageID not found."), http.StatusInternalServerError) return } var b map[string]interface{} if err := getRequestJson(w, r, &b); err != nil { handleError(c, w, err, http.StatusBadRequest) return } intID, err := strconv.ParseInt(keyIDStr, 10, 64) if err != nil { handleError(c, w, err, http.StatusBadRequest) return } pageKey := model.NewPageKey(c, intID) var p model.Page if err := ds.Get(c, pageKey, &p); err != nil { handleError(c, w, err, http.StatusBadRequest) return } err = datastore.RunInTransaction(c, func(c context.Context) error { // TODO make async for id, value := range b { log.Infof(c, "saving block. id:%s, value:%s", id, value) r := regexp.MustCompile(`^ctpl_block:(true|false):(\w+):(\d+)$`) gr := r.FindStringSubmatch(id) if gr == nil { return errors.New("illegal block id:" + id) } global, err := strconv.ParseBool(gr[1]) if err != nil { return err } areaID := gr[2] strBlockID := gr[3] blockID, err := strconv.ParseInt(strBlockID, 10, 64) if err != nil { return err } var pkey *datastore.Key if global { pkey = model.NewGlobalPageKey(c) } else { pkey = pageKey } akey := model.NewAreaKey(c, areaID, pkey) bkey := model.NewHTMLBlockKey(c, blockID, akey) var block model.HTMLBlock if err := ds.Get(c, bkey, &block); err != nil { return errors.WrapOr(err) } var ok bool block.Value, ok = value.(string) if !ok { return errors.New( fmt.Sprintf("illegal block value type :%T", value)) } if err = ds.Put(c, &block); err != nil { return errors.WrapOr(err) } // save backup entity when HTMLBlock saved. blocks := []*model.HTMLBlock{&block} backupHTMLBlockFunc.Call(c, uuid.New(), blocks) } return nil }, &datastore.TransactionOptions{XG: true}) if err != nil { handleError(c, w, err, http.StatusInternalServerError) return } }
func getAreaAndBlocksAsync(c context.Context, pkey *datastore.Key, areaName string) <-chan func() (*model.Area, []model.Block, error) { ch := make(chan func() (*model.Area, []model.Block, error)) go func() { var area model.Area area.Key = model.NewAreaKey(c, areaName, pkey) err := datastore.RunInTransaction(c, func(c context.Context) error { err := ds.Get(c, area.Key, &area) if err != nil && errors.Root(err) == datastore.ErrNoSuchEntity { // create if not exist // TODO make blocks extendable & initially zero blocks var block model.HTMLBlock block.Key = model.NewHTMLBlockIncompleteKey(c, area.Key) block.Value = areaName + ": edit here." err = ds.Put(c, &block) if err != nil { return err } area.Name = areaName area.Blocks = []*datastore.Key{block.Key} err = ds.Put(c, &area) if err != nil { return err } } return err }, nil) if err != nil { ch <- func() (*model.Area, []model.Block, error) { return nil, nil, err } return } blockChans := []<-chan func() (*model.HTMLBlock, error){} for _, blockKey := range area.Blocks { blockCh := getHTMLBlockAsync(c, blockKey) blockChans = append(blockChans, blockCh) } blocks := []model.Block{} for _, blockCh := range blockChans { b, err := (<-blockCh)() if err != nil { // TODO block not found blocks = append(blocks, &model.HTMLBlock{Value: "block not found."}) } else { blocks = append(blocks, b) } } ch <- func() (*model.Area, []model.Block, error) { return &area, blocks, nil } }() return ch }