func renderPage(id string, u *user.User, c context.Context, w http.ResponseWriter, r *http.Request, edit bool) { var pageKey *datastore.Key pID, err := strconv.ParseInt(id, 10, 64) if err != nil { // check alias paKey := model.NewPageAliasKey(c, id) var pa model.PageAlias if err := ds.Get(c, paKey, &pa); err != nil { handleError(c, w, err, http.StatusNotFound) return } pID = pa.PageKey.IntID() pageKey = pa.PageKey } else { pageKey = model.NewPageKey(c, pID) } var p model.Page if err := ds.Get(c, pageKey, &p); err != nil { handleError(c, w, err, http.StatusNotFound) return } if edit { if u == nil { loginURL, _ := user.LoginURL(c, p.URLBase()+common.EDIT_PAGE_EXT) http.Redirect(w, r, loginURL, http.StatusFound) return } else if !u.Admin { // TODO: prepare error page http.Redirect(w, r, "/caterpillar/error/invalidUser", http.StatusFound) return } } leaf := leaves[p.Leaf] if leaf == nil { errmsg := fmt.Sprintf("leaf not found:" + p.Leaf) handleError(c, w, errors.New(errmsg), http.StatusNotFound) return } tparam := struct { Properties map[string]interface{} Areas map[string]interface{} User *user.User Edit bool PageID int64 ViewURL string EditURL string PagesURL string LogoutURL string }{ make(map[string]interface{}), make(map[string]interface{}), u, edit, pID, "", "", "", "", } if u != nil { tparam.PagesURL = "/caterpillar/static/mng/#/queryPage" purl := p.URLBase() tparam.ViewURL = purl + common.VIEW_PAGE_EXT tparam.EditURL = purl + common.EDIT_PAGE_EXT logoutURL, err := user.LogoutURL(c, tparam.ViewURL) if err != nil { // only log applog.Warningf(c, "cannot get logoutURL. err:%v", err) } tparam.LogoutURL = logoutURL } futureProps := make(map[string]<-chan func() (*model.PageProperty, error)) futureAreas := make(map[string]<-chan func() (*model.Area, []model.Block, error)) for _, hole := range leaf.Wormholes { var pkey *datastore.Key if hole.Global { pkey = model.NewGlobalPageKey(c) } else { pkey = pageKey } switch hole.Type { case PROPERTY: propkey := model.NewPagePropertyKey(c, hole.Name, pkey) ch := getPagePropertyAsync(c, propkey) futureProps[hole.Name] = ch case AREA: ch := getAreaAndBlocksAsync(c, pkey, hole.Name) futureAreas[hole.Name] = ch } } pageURLs := make(map[string]string) for _, hole := range leaf.Wormholes { switch hole.Type { case PROPERTY: prop, err := (<-futureProps[hole.Name])() if err == nil { tparam.Properties[hole.Name] = prop.Value } else { // TODO handle error applog.Errorf(c, "%s", err) } case AREA: area, blocks, err := (<-futureAreas[hole.Name])() if err == nil { areasrc := renderArea(hole.Global, area, blocks, edit) if !edit { futurePages := make(map[string]<-chan func() (*model.Page, error)) urls := pageUrlRegex.FindAllStringSubmatch(areasrc, -1) for _, url := range urls { purl := url[0] if _, exists := pageURLs[purl]; exists { continue } if _, exists := futurePages[purl]; exists { continue } pageID, err := strconv.ParseInt(url[1], 10, 64) if err != nil { // TODO handle error applog.Errorf(c, "%s", err) continue } pkey := model.NewPageKey(c, pageID) futurePages[purl] = getPageAsync(c, pkey) } for purl, ch := range futurePages { page, err := (<-ch)() if err != nil { // TODO handle error applog.Errorf(c, "%s", err) continue } pageURLs[purl] = page.URLBase() + common.VIEW_PAGE_EXT } areasrc = pageUrlRegex.ReplaceAllStringFunc(areasrc, func(s string) string { if r, true := pageURLs[s]; true { return r } return s }) } tparam.Areas[hole.Name] = template.HTML(areasrc) } else { // TODO handle error applog.Errorf(c, "%s", err) } } } // TODO: validate reserved page name property // or put some prefix? tparam.Properties["name"] = p.Name // TODO: resolve charset from somewhere w.Header().Set("Content-Type", "text/html; charset=utf-8") if err = leaf.Template.Execute(w, tparam); err != nil { handleError(c, w, err, http.StatusInternalServerError) return } return }