package table import ( "fmt" "net/url" "os" "path/filepath" "strings" "time" "github.com/google/uuid" "github.com/yaoapp/gou/fs" "github.com/yaoapp/gou/model" gouProcess "github.com/yaoapp/gou/process" "github.com/yaoapp/gou/types" "github.com/yaoapp/kun/any" "github.com/yaoapp/kun/exception" "github.com/yaoapp/kun/log" "github.com/yaoapp/kun/maps" "github.com/yaoapp/yao/helper" "github.com/yaoapp/yao/widgets/app" ) // Export process func exportProcess() { // Table Data Operations gouProcess.Register("yao.table.setting", processSetting) gouProcess.Register("yao.table.xgen", processXgen) gouProcess.Register("yao.table.component", processComponent) gouProcess.Register("yao.table.upload", processUpload) gouProcess.Register("yao.table.download", processDownload) gouProcess.Register("yao.table.search", processSearch) gouProcess.Register("yao.table.get", processGet) gouProcess.Register("yao.table.find", processFind) gouProcess.Register("yao.table.save", processSave) gouProcess.Register("yao.table.create", processCreate) gouProcess.Register("yao.table.insert", processInsert) gouProcess.Register("yao.table.update", processUpdate) gouProcess.Register("yao.table.updatewhere", processUpdateWhere) gouProcess.Register("yao.table.updatein", processUpdateIn) gouProcess.Register("yao.table.delete", processDelete) gouProcess.Register("yao.table.deletewhere", processDeleteWhere) gouProcess.Register("yao.table.deletein", processDeleteIn) gouProcess.Register("yao.table.export", processExport) // DSL Operations gouProcess.Register("yao.table.exists", processExists) gouProcess.Register("yao.table.read", processRead) gouProcess.Register("yao.table.list", processList) gouProcess.Register("yao.table.dsl", processDSL) gouProcess.Register("yao.table.load", processLoad) gouProcess.Register("yao.table.reload", processReload) gouProcess.Register("yao.table.unload", processUnload) } func processXgen(process *gouProcess.Process) interface{} { tab := MustGet(process) data := process.ArgsMap(1, map[string]interface{}{}) excludes := app.Permissions(process, "tables", tab.ID) setting, err := tab.Xgen(data, excludes) if err != nil { exception.New(err.Error(), 500).Throw() } return setting } func processDownload(process *gouProcess.Process) interface{} { process.ValidateArgNums(4) tab := MustGet(process) field := process.ArgsString(1) file := process.ArgsString(2) tokenString := process.ArgsString(3) isAppRoot := process.ArgsInt(4, 0) // checking ext := fs.ExtName(file) if _, has := fs.DownloadWhitelist[ext]; !has { exception.New("%s.%s .%s file does not allow", 403, tab.ID, field, ext).Throw() } // Auth tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer ")) if tokenString == "" { exception.New("%s.%s No permission", 403, tab.ID, field).Throw() } claims := helper.JwtValidate(tokenString) // Get Process name name := "fs.system.Download" if tab.Action.Download.Process != "" { name = tab.Action.Download.Process } // The root path of the application the Upload Component props.appRoot=true if isAppRoot == 1 { name = "fs.app.Download" } // Create process p, err := gouProcess.Of(name, file) if err != nil { log.Error("[downalod] %s.%s %s", tab.ID, field, err.Error()) exception.New("[downalod] %s.%s %s", 400, tab.ID, field, err.Error()).Throw() } // Excute process err = p.WithGlobal(process.Global).WithSID(claims.SID).Execute() if err != nil { log.Error("[downalod] %s.%s %s", tab.ID, field, err.Error()) exception.New("[downalod] %s.%s %s", 500, tab.ID, field, err.Error()).Throw() } defer p.Release() return p.Value() } func processUpload(process *gouProcess.Process) interface{} { process.ValidateArgNums(4) tab := MustGet(process) xpath, _ := url.QueryUnescape(process.ArgsString(1)) method, _ := url.QueryUnescape(process.ArgsString(2)) key := fmt.Sprintf("%s.$%s", xpath, method) // get cloud props cProp, has := tab.CProps[key] if !has { exception.New("%s does not exist", 400, key).Throw() } // $file.file tmpfile, ok := process.Args[3].(types.UploadFile) if !ok { exception.New("parameters error: %v", 400, process.Args[3]).Throw() } // execute upload res, err := cProp.ExecUpload(process, tmpfile) if err != nil { exception.New(err.Error(), 500).Throw() } if file, ok := res.(string); ok { field := strings.TrimSuffix(xpath, ".edit.props") file = fmt.Sprintf("/api/__yao/table/%s/download/%s?name=%s", tab.ID, url.QueryEscape(field), file) return file } return res } func processComponent(process *gouProcess.Process) interface{} { process.ValidateArgNums(3) tab := MustGet(process) xpath, _ := url.QueryUnescape(process.ArgsString(1)) method, _ := url.QueryUnescape(process.ArgsString(2)) key := fmt.Sprintf("%s.$%s", xpath, method) // get cloud props cProp, has := tab.CProps[key] if !has { exception.New("%s does not exist", 400, key).Throw() } // :query query := map[string]interface{}{} if process.NumOfArgsIs(4) { query = process.ArgsMap(3, map[string]interface{}{}) } // execute query res, err := cProp.ExecQuery(process, query) if err != nil { exception.New(err.Error(), 500).Throw() } return res } func processSetting(process *gouProcess.Process) interface{} { tab := MustGet(process) process.Args = append(process.Args, process.Args[0]) // table name return tab.Action.Setting.MustExec(process) } func processSearch(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.Search.MustExec(process) } func processGet(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.Get.MustExec(process) } func processSave(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.Save.MustExec(process) } func processCreate(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.Create.MustExec(process) } func processFind(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.Find.MustExec(process) } func processInsert(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.Insert.MustExec(process) } func processUpdate(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.Update.MustExec(process) } func processUpdateWhere(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.UpdateWhere.MustExec(process) } func processUpdateIn(process *gouProcess.Process) interface{} { process.ValidateArgNums(3) tab := MustGet(process) ids := strings.Split(process.ArgsString(1), ",") process.Args[1] = model.QueryParam{ Wheres: []model.QueryWhere{ {Column: tab.Layout.Primary, OP: "in", Value: ids}, }, } return tab.Action.UpdateIn.MustExec(process) } func processDelete(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.Delete.MustExec(process) } func processDeleteWhere(process *gouProcess.Process) interface{} { tab := MustGet(process) return tab.Action.DeleteWhere.MustExec(process) } func processDeleteIn(process *gouProcess.Process) interface{} { process.ValidateArgNums(2) tab := MustGet(process) ids := strings.Split(process.ArgsString(1), ",") process.Args[1] = model.QueryParam{ Wheres: []model.QueryWhere{ {Column: tab.Layout.Primary, OP: "in", Value: ids}, }, } return tab.Action.DeleteIn.MustExec(process) } // processExport yao.table.Export (:table, :queryParam, :chunkSize) func processExport(process *gouProcess.Process) interface{} { process.ValidateArgNums(1) tab := MustGet(process) // 0 params := process.ArgsQueryParams(1, types.QueryParam{}) pagesize := process.ArgsInt(2, 50) log.Trace("[table] export %s %v %d", tab.ID, params, pagesize) // Filename fingerprint := uuid.NewString() dir := time.Now().Format("20060102") filename := filepath.Join(string(os.PathSeparator), dir, fmt.Sprintf("%s.xlsx", fingerprint)) // Create Data Path fs := fs.MustGet("system") if has, _ := fs.Exists(dir); !has { fs.MkdirAll(dir, uint32(os.ModePerm)) } // Query page := 1 for page > 0 { process.Args = []interface{}{tab.ID, params, page, pagesize} data, err := tab.Action.Search.Exec(process) if err != nil { log.Error("[table] export error %s", err.Error()) page = -1 continue } res, ok := data.(map[string]interface{}) if !ok { res, ok = data.(maps.MapStrAny) if !ok { log.Error("[table] export Search Action response data error %#v", data) page = -1 continue } } if _, ok := res["next"]; !ok { page = -1 continue } size := pagesize if _, ok := res["pagesize"]; ok { size = any.Of(res["pagesize"]).CInt() } // Export err = tab.Export(filename, res["data"], page, size) if err != nil { log.Error("Export %s %s", tab.ID, err.Error()) } page = any.Of(res["next"]).CInt() } return filename } // processLoad yao.table.Load table_name file func processLoad(process *gouProcess.Process) interface{} { process.ValidateArgNums(1) // Load from source if process.NumOfArgs() >= 3 { id := process.ArgsString(0) source := process.ArgsString(2) _, err := LoadSourceSync([]byte(source), id) if err != nil { exception.New(err.Error(), 500).Throw() } return nil } // Load from file file := process.ArgsString(0) if file == "" { exception.New("file is required", 400).Throw() } file = strings.TrimPrefix(file, string(os.PathSeparator)) return LoadFileSync("tables", file) } // processReload yao.table.Reload table_name func processReload(process *gouProcess.Process) interface{} { process.ValidateArgNums(1) tab := MustGet(process) // 0 _, err := tab.Reload() if err != nil { exception.New(err.Error(), 500).Throw() } return nil } // processUnload yao.table.Unload table_name func processUnload(process *gouProcess.Process) interface{} { process.ValidateArgNums(1) Unload(process.ArgsString(0)) return nil } // processRead yao.table.Read table_name func processRead(process *gouProcess.Process) interface{} { process.ValidateArgNums(1) tab := MustGet(process) // 0 return string(tab.Read()) } // processExists yao.table.Exists table_name func processExists(process *gouProcess.Process) interface{} { process.ValidateArgNums(1) return Exists(process.ArgsString(0)) } // processList returns all loaded tables func processList(process *gouProcess.Process) interface{} { tables := GetTables() return tables } // GetTables returns all loaded tables func GetTables() map[string]*DSL { return Tables } // processGetDSL returns the DSL of a table by its ID func processDSL(process *gouProcess.Process) interface{} { process.ValidateArgNums(1) id := process.ArgsString(0) if !Exists(id) { exception.New("table %s does not exist", 404, id).Throw() } tab := MustGet(process) // 0 return tab }