// Delete a file OR dir. See NewFile for controversy about filenames and extensions. func DeleteFile(opt map[string]interface{}, inp map[string][]string, root, host string) error { if !CanModifyTemplate(opt) { return fmt.Errorf(cant_mod_public) } rule := map[string]interface{}{ "filepath": "must", } dat, e_err := extract.New(rule).Extract(inp) if e_err != nil { return e_err } fp := dat["filepath"].(string) full_p := filepath.Join(root, scut.GetTPath(opt, host), fp) var err error if IsDir(fp) { err = os.RemoveAll(full_p) } else { err = os.Remove(full_p) } if err != nil { fmt.Println(err) return fmt.Errorf("Can't delete file or directory. Probably it does not exist.") } return nil }
// Since we don't include the template name into the url, only "template", we have to extract the template name from the opt here. // Example: xyz.com/template/style.css // xyz.com/tpl/admin/style.css func serveTemplateFile(w http.ResponseWriter, req *http.Request, uni *context.Uni) { if uni.Paths[1] == "template" { p := scut.GetTPath(uni.Opt, uni.Req.Host) http.ServeFile(w, req, filepath.Join(uni.Root, p, strings.Join(uni.Paths[2:], "/"))) } else { // "tpl" http.ServeFile(w, req, filepath.Join(uni.Root, "modules", uni.Paths[2], "tpl", strings.Join(uni.Paths[3:], "/"))) } }
// New file OR dir. Filenames without extensions became dirs. RETHINK: This way we lose the ability to create files without extensions. // Only accessed member of opt will be "TplIsPrivate" in scut.GetTPath. TODO: this is ugly. func NewFile(opt map[string]interface{}, inp map[string][]string, root, host string) error { if !CanModifyTemplate(opt) { return fmt.Errorf(cant_mod_public) } rule := map[string]interface{}{ "filepath": "must", "where": "must", } dat, e_err := extract.New(rule).Extract(inp) if e_err != nil { return e_err } fp := dat["filepath"].(string) where := dat["where"].(string) if IsDir(fp) { return os.Mkdir(filepath.Join(root, scut.GetTPath(opt, host), where, fp), os.ModePerm) } return ioutil.WriteFile(filepath.Join(root, scut.GetTPath(opt, host), where, fp), []byte(""), os.ModePerm) }
// Displays a display point. func D(uni *context.Uni) { points, points_exist := uni.Dat["_points"] var point string if points_exist { point = points.([]string)[0] } else { p := uni.Req.URL.Path if p == "/" { point = "index" } else { point = p } } queries, queries_exists := jsonp.Get(uni.Opt, "Display-points."+point+".queries") if queries_exists { qmap, ok := queries.(map[string]interface{}) if ok { runQueries(uni, qmap) } } BeforeDisplay(uni) // While it is not the cheapest solution to convert bson.ObjectIds to strings here, where we have to iterate trough all values, // it is still better than remembering (and forgetting) to convert it at every specific place. scut.IdsToStrings(uni.Dat) langs, _ := jsonp.Get(uni.Dat, "_user.languages") // _user always has language member langs_s := toStringSlice(langs) loc, _ := display_model.LoadLocStrings(uni.Dat, langs_s, uni.Root, scut.GetTPath(uni.Opt, uni.Req.Host), nil) // TODO: think about errors here. if loc != nil { uni.Dat["loc"] = loc } if _, isjson := uni.Req.Form["json"]; isjson { putJSON(uni) return } else { err := DisplayFile(uni, point) if err != nil { uni.Dat["missing_file"] = point err_404 := DisplayFile(uni, "404") if err_404 != nil { uni.Put("Cant find file: ", point) } } } }
// Forks a public template into a private one: creates a deep recursive copy of the whole directory tree, so the user // can edit his own template files as he wishes. func ForkPublic(db *mgo.Database, opt map[string]interface{}, root, host string) error { if CanModifyTemplate(opt) { return fmt.Errorf("Template is already private.") } from := filepath.Join(root, scut.GetTPath(opt, host)) to := filepath.Join(root, "templates", "private", host, scut.TemplateName(opt)) copy_err := copyrecur.CopyDir(from, to) if copy_err != nil { // && copy_err.Error() != "Destination already exists" return copy_err } id := basic.CreateOptCopy(db) q := m{"_id": id} upd := m{ "$set": m{ "TplIsPrivate": true, }, } return db.C("options").Update(q, upd) }
// Loads localization, template functions and executes the template. func prepareAndExec(uni *context.Uni, file string) { root := uni.Root host := uni.Req.Host dat := uni.Dat opt := uni.Opt w := uni.W langs, has := jsonp.Get(dat, "_user.languages") // _user should always has languages field if !has { langs = []string{"en"} } langs_s := toStringSlice(langs) if !has { langs = []string{"en"} } loc, _ := display_model.LoadLocTempl(file, langs_s, root, scut.GetTPath(opt, host), nil) // TODO: think about errors here. dat["loc"] = merge(dat["loc"], loc) funcMap := template.FuncMap(builtins(uni)) t, _ := template.New("tpl").Funcs(funcMap).Parse(string(file)) w.Header().Set("Content-Type", "text/html; charset=utf-8") t.Execute(w, dat) // TODO: watch for errors in execution. }
// Extracts all requires ( {{require example.t}} ) from a given file. // Takes into account fallback files too. // First it checks if the file exists in the current template. If yes, the link will point to that file. // If not, then the link will point to the fallback module file. // TODO: Case when the required file does not exists anywhere is not handled. func ReqLinks(opt map[string]interface{}, file, root, host string) []ReqLink { pos := require.RequirePositions(file) ret := []ReqLink{} for _, v := range pos { fi := file[v[0]+10 : v[1]-2] // cut {{require anything/anything.t}} => anything/anything.t var typ, path, name string exists_in_template, err := Exists(filepath.Join(root, scut.GetTPath(opt, host), fi)) if err != nil { continue } if exists_in_template { typ = scut.TemplateType(opt) path = fi name = scut.TemplateName(opt) } else { path = scut.GetModTPath(fi)[1] typ = "mod" name = strings.Split(fi, "/")[0] } rl := ReqLink{typ, name, path} ret = append(ret, rl) } return ret }