Esempio n. 1
0
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
}