rest.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. package rest
  2. import (
  3. "context"
  4. "encoding/csv"
  5. "encoding/json"
  6. "fmt"
  7. "git.nspix.com/golang/micro/gateway/http"
  8. errpkg "git.nspix.com/golang/rest/v3/error"
  9. "git.nspix.com/golang/rest/v3/inflector"
  10. "gorm.io/gorm"
  11. "gorm.io/gorm/clause"
  12. httppkg "net/http"
  13. "path"
  14. "reflect"
  15. "strconv"
  16. "strings"
  17. )
  18. const (
  19. HttpAccessDenied = 8004 //拒绝访问
  20. HttpInvalidPayload = 8002 //请求内容无效
  21. HttpRequestCallbackFailed = 8003 //执行回调失败
  22. HttpValidateFailed = 8008 //数据校验失败
  23. HttpDatabaseQueryFailed = 8010 //查询失败
  24. HttpDatabaseFindFailed = 8011 //查找失败
  25. HttpDatabaseCreateFailed = 8012 //创建失败
  26. HttpDatabaseUpdateFailed = 8013 //更新失败
  27. HttpDatabaseDeleteFailed = 8014 //删除失败
  28. HttpDatabaseExportFailed = 8015 //数据导出失败
  29. HTTPUnknownFailed = 9001 //未知错误
  30. )
  31. const (
  32. ErrorAccessDeniedMessage = "access denied"
  33. )
  34. const (
  35. restCtxRequest = "rest-ctx-request"
  36. restCtxResponse = "rest-ctx-response"
  37. restCtxHttpctx = "rest-ctx-httpctx"
  38. )
  39. const (
  40. OperatorEqual = "eq"
  41. OperatorGreaterThan = "gt"
  42. OperatorGreaterEqual = "ge"
  43. OperatorLessThan = "lt"
  44. OperatorLessEqual = "le"
  45. OperatorLike = "like"
  46. OperatorBetween = "between"
  47. )
  48. type (
  49. DiffAttr struct {
  50. Column string `json:"column"`
  51. Label string `json:"label"`
  52. OldValue interface{} `json:"old_value"`
  53. NewValue interface{} `json:"new_value"`
  54. }
  55. Condition struct {
  56. Column string `json:"column"`
  57. Expr string `json:"expr"`
  58. Value interface{} `json:"value,omitempty"`
  59. Values []interface{} `json:"values,omitempty"`
  60. }
  61. Restful struct {
  62. model Model
  63. opts *Options
  64. reflectType reflect.Type
  65. reflectValue reflect.Value
  66. singularName string
  67. pluralizeName string
  68. statement *gorm.Statement
  69. primaryKey string
  70. }
  71. )
  72. // getScenarioUrl 获取某个场景下HTTP请求的URL
  73. func (r *Restful) getScenarioUrl(scenario string) string {
  74. var uri string
  75. switch scenario {
  76. case ScenarioList:
  77. uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.pluralizeName
  78. case ScenarioView:
  79. uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName + "/:id"
  80. case ScenarioCreate:
  81. uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName
  82. case ScenarioUpdate:
  83. uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName + "/:id"
  84. case ScenarioDelete:
  85. uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName + "/:id"
  86. case ScenarioExport:
  87. uri = r.opts.ApiPrefix + "/" + r.model.ModuleName() + "/" + r.singularName + "-export"
  88. }
  89. return path.Clean(uri)
  90. }
  91. // getScenarioHandle 获取某个场景下HTTP请求的处理回调
  92. func (r *Restful) getScenarioHandle(scenario string) http.HandleFunc {
  93. var handleFunc http.HandleFunc
  94. switch scenario {
  95. case ScenarioList:
  96. handleFunc = r.actionIndex
  97. case ScenarioView:
  98. handleFunc = r.actionView
  99. case ScenarioCreate:
  100. handleFunc = r.actionCreate
  101. case ScenarioUpdate:
  102. handleFunc = r.actionUpdate
  103. case ScenarioDelete:
  104. handleFunc = r.actionDelete
  105. case ScenarioExport:
  106. handleFunc = r.actionExport
  107. }
  108. return handleFunc
  109. }
  110. func (r *Restful) setFieldValue(model reflect.Value, column string, value interface{}) {
  111. var (
  112. name string
  113. )
  114. refVal := reflect.Indirect(model)
  115. for _, field := range r.statement.Schema.Fields {
  116. if field.DBName == column {
  117. name = field.Name
  118. break
  119. } else if field.Name == column {
  120. name = column
  121. break
  122. }
  123. }
  124. if name == "" {
  125. return
  126. }
  127. fieldVal := refVal.FieldByName(name)
  128. if fieldVal.CanSet() {
  129. fieldVal.Set(reflect.ValueOf(value))
  130. }
  131. }
  132. //getFieldValue get field value from reflect value
  133. func (r *Restful) getFieldValue(model reflect.Value, column string) interface{} {
  134. var (
  135. name string
  136. )
  137. refVal := reflect.Indirect(model)
  138. for _, field := range r.statement.Schema.Fields {
  139. if field.DBName == column {
  140. name = field.Name
  141. break
  142. } else if field.Name == column {
  143. name = column
  144. break
  145. }
  146. }
  147. if name == "" {
  148. return nil
  149. }
  150. fieldVal := refVal.FieldByName(name)
  151. return fieldVal.Interface()
  152. }
  153. func (r *Restful) hasScenario(s string) bool {
  154. if v, ok := r.model.(FlexibleModel); ok {
  155. for _, n := range v.Scenarios() {
  156. if s == n {
  157. return true
  158. }
  159. }
  160. return false
  161. }
  162. return true
  163. }
  164. func (r *Restful) findCondition(schema *Schema, conditions []*Condition) *Condition {
  165. for _, cond := range conditions {
  166. if cond.Column == schema.Column {
  167. return cond
  168. }
  169. }
  170. return nil
  171. }
  172. func (r *Restful) prepareConditions(ctx context.Context, requestCtx *http.Context, query *Query, schemas []*Schema) (err error) {
  173. var (
  174. ok bool
  175. skip bool
  176. formValue string
  177. model interface{}
  178. activeModel ActiveModel
  179. )
  180. model = reflect.New(r.reflectType).Interface()
  181. if r.opts.Delegate != nil {
  182. if err = r.opts.Delegate.BeforeQuery(ctx, query); err != nil {
  183. return
  184. }
  185. }
  186. if activeModel, ok = model.(ActiveModel); ok {
  187. if err = activeModel.OnBeforeQuery(ctx, query); err != nil {
  188. return
  189. }
  190. }
  191. if requestCtx.Request().Method == httppkg.MethodPut || requestCtx.Request().Method == httppkg.MethodPost {
  192. conditions := make([]*Condition, 0)
  193. if err = requestCtx.Bind(&conditions); err != nil {
  194. return
  195. }
  196. for _, schema := range schemas {
  197. cond := r.findCondition(schema, conditions)
  198. if cond == nil {
  199. continue
  200. }
  201. switch schema.Format {
  202. case FormatInteger, FormatFloat, FormatTimestamp, FormatDatetime, FormatDate, FormatTime:
  203. switch cond.Expr {
  204. case OperatorBetween:
  205. if len(cond.Values) == 2 {
  206. query.AndFilterWhere(NewCond(schema.Column, cond.Values[0]).WithExpr(">="))
  207. query.AndFilterWhere(NewCond(schema.Column, cond.Values[1]).WithExpr("<="))
  208. }
  209. case OperatorGreaterThan:
  210. query.AndFilterWhere(NewCond(schema.Column, cond.Value).WithExpr(">"))
  211. case OperatorGreaterEqual:
  212. query.AndFilterWhere(NewCond(schema.Column, cond.Value).WithExpr(">="))
  213. case OperatorLessThan:
  214. query.AndFilterWhere(NewCond(schema.Column, cond.Value).WithExpr("<"))
  215. case OperatorLessEqual:
  216. query.AndFilterWhere(NewCond(schema.Column, cond.Value).WithExpr("<="))
  217. default:
  218. query.AndFilterWhere(NewCond(schema.Column, cond.Value))
  219. }
  220. default:
  221. switch cond.Expr {
  222. case OperatorLike:
  223. query.AndFilterWhere(NewCond(schema.Column, cond.Value).WithExpr("LIKE"))
  224. default:
  225. query.AndFilterWhere(NewCond(schema.Column, cond.Value))
  226. }
  227. }
  228. }
  229. } else {
  230. //处理默认的搜索
  231. for _, schema := range schemas {
  232. skip = false
  233. if skip {
  234. continue
  235. }
  236. if schema.Native == 0 {
  237. continue
  238. }
  239. formValue = requestCtx.FormValue(schema.Column)
  240. switch schema.Format {
  241. case FormatString, FormatText:
  242. if schema.Attribute.Match == MatchExactly {
  243. query.AndFilterWhere(NewCond(schema.Column, formValue))
  244. } else {
  245. query.AndFilterWhere(NewCond(schema.Column, formValue).WithExpr("LIKE"))
  246. }
  247. case FormatTime, FormatDate, FormatDatetime, FormatTimestamp:
  248. var sep string
  249. seps := []byte{',', '/'}
  250. for _, s := range seps {
  251. if strings.IndexByte(formValue, s) > -1 {
  252. sep = string(s)
  253. }
  254. }
  255. if ss := strings.Split(formValue, sep); len(ss) == 2 {
  256. query.AndFilterWhere(
  257. NewCond(schema.Column, strings.TrimSpace(ss[0])).WithExpr(">="),
  258. NewCond(schema.Column, strings.TrimSpace(ss[1])).WithExpr("<="),
  259. )
  260. } else {
  261. query.AndFilterWhere(NewCond(schema.Column, formValue))
  262. }
  263. case FormatInteger, FormatFloat:
  264. query.AndFilterWhere(NewCond(schema.Column, formValue))
  265. default:
  266. if schema.Type == TypeString {
  267. if schema.Attribute.Match == MatchExactly {
  268. query.AndFilterWhere(NewCond(schema.Column, formValue))
  269. } else {
  270. query.AndFilterWhere(NewCond(schema.Column, formValue).WithExpr("LIKE"))
  271. }
  272. } else {
  273. query.AndFilterWhere(NewCond(schema.Column, formValue))
  274. }
  275. }
  276. }
  277. }
  278. //处理排序
  279. sortPar := requestCtx.FormValue("sort")
  280. if sortPar != "" {
  281. sorts := strings.Split(sortPar, ",")
  282. for _, s := range sorts {
  283. if s[0] == '-' {
  284. query.OrderBy(s[1:], "DESC")
  285. } else {
  286. if s[0] == '+' {
  287. query.OrderBy(s[1:], "ASC")
  288. } else {
  289. query.OrderBy(s, "ASC")
  290. }
  291. }
  292. }
  293. }
  294. if activeModel, ok = model.(ActiveModel); ok {
  295. err = activeModel.OnAfterQuery(ctx, query)
  296. }
  297. if r.opts.Delegate != nil {
  298. err = r.opts.Delegate.AfterQuery(ctx, query)
  299. }
  300. return
  301. }
  302. func (r *Restful) createContext(httpCtx *http.Context) context.Context {
  303. ctx := httpCtx.Request().Context()
  304. if ctx == nil {
  305. ctx = context.Background()
  306. }
  307. ctx = context.WithValue(ctx, restCtxRequest, httpCtx.Request())
  308. ctx = context.WithValue(ctx, restCtxResponse, httpCtx.Response())
  309. ctx = context.WithValue(ctx, restCtxHttpctx, httpCtx)
  310. return ctx
  311. }
  312. func (r *Restful) actionIndex(httpCtx *http.Context) (err error) {
  313. var (
  314. page int
  315. pageSize int
  316. pageIndex int
  317. query *Query
  318. namespace string
  319. )
  320. if !r.hasScenario(ScenarioList) {
  321. return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
  322. }
  323. ctx := r.createContext(httpCtx)
  324. namespace = httpCtx.ParamValue(NamespaceVariable)
  325. page, _ = strconv.Atoi(httpCtx.FormValue("page"))
  326. pageSize, _ = strconv.Atoi(httpCtx.FormValue("pagesize"))
  327. if pageSize <= 0 {
  328. pageSize = 15
  329. }
  330. pageIndex = page
  331. if pageIndex > 0 {
  332. pageIndex--
  333. }
  334. sliceValue := reflect.MakeSlice(reflect.SliceOf(r.reflectType), 0, 0)
  335. models := reflect.New(sliceValue.Type())
  336. models.Elem().Set(sliceValue)
  337. query = NewQuery(r.opts.DB)
  338. searchSchemas := r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioSearch)
  339. indexSchemas := r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioList)
  340. if err = r.prepareConditions(ctx, httpCtx, query, searchSchemas); err != nil {
  341. return httpCtx.Error(HttpDatabaseQueryFailed, err.Error())
  342. }
  343. if r.opts.EnableNamespace {
  344. query.AndFilterWhere(NewQueryCondition(NamespaceField, namespace))
  345. }
  346. query.Offset(pageIndex * pageSize).Limit(pageSize)
  347. if err = query.All(models.Interface()); err != nil {
  348. return httpCtx.Error(HttpDatabaseQueryFailed, err.Error())
  349. }
  350. resp := &ListResponse{
  351. Page: page,
  352. PageSize: pageSize,
  353. TotalCount: query.Limit(0).Offset(0).Count(r.model),
  354. }
  355. if resp.TotalCount > 0 {
  356. resp.Data = r.opts.Formatter.formatModels(ctx, models.Interface(), indexSchemas, r.statement)
  357. } else {
  358. resp.Data = make([]string, 0)
  359. }
  360. return httpCtx.Success(resp)
  361. }
  362. func (r *Restful) actionCreate(httpCtx *http.Context) (err error) {
  363. var (
  364. errTx error
  365. namespace string
  366. model interface{}
  367. schemas []*Schema
  368. refModel reflect.Value
  369. diffAttrs []*DiffAttr
  370. )
  371. ctx := r.createContext(httpCtx)
  372. diffAttrs = make([]*DiffAttr, 0, 10)
  373. if !r.hasScenario(ScenarioCreate) {
  374. return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
  375. }
  376. namespace = httpCtx.ParamValue(NamespaceVariable)
  377. refModel = reflect.New(r.reflectType)
  378. model = refModel.Interface()
  379. if err = httpCtx.Bind(model); err != nil {
  380. return httpCtx.Error(HttpInvalidPayload, err.Error())
  381. }
  382. schemas = r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioCreate)
  383. //global set field value
  384. r.setFieldValue(refModel, NamespaceField, namespace)
  385. r.setFieldValue(refModel, CreatedByField, httpCtx.ParamValue(UserVariable))
  386. r.setFieldValue(refModel, CreatedDeptField, httpCtx.ParamValue(DepartmentVariable))
  387. r.setFieldValue(refModel, UpdatedByField, httpCtx.ParamValue(UserVariable))
  388. r.setFieldValue(refModel, UpdatedDeptField, httpCtx.ParamValue(DepartmentVariable))
  389. if err = r.opts.DB.Transaction(func(tx *gorm.DB) error {
  390. if r.opts.Delegate != nil {
  391. if errTx = r.opts.Delegate.BeforeCreate(ctx, model); errTx != nil {
  392. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  393. }
  394. if errTx = r.opts.Delegate.BeforeSave(ctx, model); errTx != nil {
  395. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  396. }
  397. }
  398. if activeModel, ok := model.(ActiveModel); ok {
  399. if errTx = activeModel.OnBeforeCreate(ctx, model); errTx != nil {
  400. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  401. }
  402. if errTx = activeModel.OnBeforeSave(ctx, model); errTx != nil {
  403. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  404. }
  405. }
  406. //创建数据
  407. if errTx = tx.Create(model).Error; errTx != nil {
  408. return errTx
  409. }
  410. //对比差异数据
  411. for _, scm := range schemas {
  412. diffAttrs = append(diffAttrs, &DiffAttr{
  413. Column: scm.Column,
  414. Label: scm.Label,
  415. OldValue: nil,
  416. NewValue: r.getFieldValue(refModel, scm.Column),
  417. })
  418. }
  419. if activeModel, ok := model.(ActiveModel); ok {
  420. if errTx = activeModel.OnAfterCreate(ctx, model, diffAttrs); errTx != nil {
  421. return httpCtx.Error(HttpRequestCallbackFailed, err.Error())
  422. }
  423. if errTx = activeModel.OnAfterSave(ctx, model, diffAttrs); errTx != nil {
  424. return httpCtx.Error(HttpRequestCallbackFailed, err.Error())
  425. }
  426. }
  427. if r.opts.Delegate != nil {
  428. if errTx = r.opts.Delegate.AfterCreate(ctx, model, diffAttrs); errTx != nil {
  429. return httpCtx.Error(HttpRequestCallbackFailed, err.Error())
  430. }
  431. if errTx = r.opts.Delegate.AfterSave(ctx, model, diffAttrs); errTx != nil {
  432. return httpCtx.Error(HttpRequestCallbackFailed, err.Error())
  433. }
  434. }
  435. return errTx
  436. }); err == nil {
  437. pkVal := r.getFieldValue(refModel, r.primaryKey)
  438. return httpCtx.Success(&CreateResponse{
  439. ID: pkVal,
  440. Topic: r.model.TableName(),
  441. State: "created",
  442. })
  443. }
  444. //form validation
  445. if validateError, ok := err.(*errpkg.StructError); ok {
  446. httpCtx.Response().Header().Set("Content-Type", "application/json")
  447. return json.NewEncoder(httpCtx.Response()).Encode(map[string]interface{}{
  448. "errno": HttpValidateFailed,
  449. "result": validateError,
  450. })
  451. }
  452. return httpCtx.Error(HttpDatabaseCreateFailed, err.Error())
  453. }
  454. func (r *Restful) actionUpdate(httpCtx *http.Context) (err error) {
  455. var (
  456. errTx error
  457. namespace string
  458. model interface{}
  459. schemas []*Schema
  460. refModel reflect.Value
  461. oldValues = make(map[string]interface{})
  462. diffs = make(map[string]interface{})
  463. diffAttrs = make([]*DiffAttr, 0)
  464. )
  465. ctx := r.createContext(httpCtx)
  466. if !r.hasScenario(ScenarioUpdate) {
  467. return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
  468. }
  469. namespace = httpCtx.ParamValue(NamespaceVariable)
  470. idStr := httpCtx.ParamValue("id")
  471. refModel = reflect.New(r.reflectType)
  472. model = refModel.Interface()
  473. //默认设置更新用户
  474. r.setFieldValue(refModel, UpdatedByField, httpCtx.ParamValue(UserVariable))
  475. r.setFieldValue(refModel, UpdatedDeptField, httpCtx.ParamValue(DepartmentVariable))
  476. conditions := map[string]interface{}{
  477. r.primaryKey: idStr,
  478. }
  479. if r.opts.EnableNamespace {
  480. conditions[NamespaceField] = namespace
  481. }
  482. if err = r.opts.DB.Where(conditions).First(model).Error; err != nil {
  483. return httpCtx.Error(HttpDatabaseFindFailed, err.Error())
  484. }
  485. schemas = r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioUpdate)
  486. for _, scm := range schemas {
  487. oldValues[scm.Column] = r.getFieldValue(refModel, scm.Column)
  488. }
  489. if err = httpCtx.Bind(model); err != nil {
  490. return httpCtx.Error(HttpInvalidPayload, err.Error())
  491. }
  492. if err = r.opts.DB.Transaction(func(tx *gorm.DB) error {
  493. if r.opts.Delegate != nil {
  494. if errTx = r.opts.Delegate.BeforeUpdate(ctx, model); errTx != nil {
  495. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  496. }
  497. if errTx = r.opts.Delegate.BeforeSave(ctx, model); errTx != nil {
  498. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  499. }
  500. }
  501. if activeModel, ok := model.(ActiveModel); ok {
  502. if errTx = activeModel.OnBeforeUpdate(ctx, model); errTx != nil {
  503. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  504. }
  505. if errTx = activeModel.OnBeforeSave(ctx, model); errTx != nil {
  506. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  507. }
  508. }
  509. //对比差异数据
  510. for _, scm := range schemas {
  511. v := r.getFieldValue(refModel, scm.Column)
  512. if oldValues[scm.Column] != v {
  513. diffs[scm.Column] = v
  514. diffAttrs = append(diffAttrs, &DiffAttr{
  515. Column: scm.Column,
  516. Label: scm.Label,
  517. OldValue: oldValues[scm.Column],
  518. NewValue: v,
  519. })
  520. }
  521. }
  522. //进行局部数据更新
  523. if len(diffs) > 0 {
  524. if errTx = tx.Model(model).Updates(diffs).Error; errTx != nil {
  525. return errTx
  526. }
  527. }
  528. if activeModel, ok := model.(ActiveModel); ok {
  529. if errTx = activeModel.OnAfterUpdate(ctx, model, diffAttrs); errTx != nil {
  530. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  531. }
  532. if errTx = activeModel.OnAfterSave(ctx, model, diffAttrs); errTx != nil {
  533. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  534. }
  535. }
  536. if r.opts.Delegate != nil {
  537. if errTx = r.opts.Delegate.AfterUpdate(ctx, model, diffAttrs); errTx != nil {
  538. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  539. }
  540. if errTx = r.opts.Delegate.AfterSave(ctx, model, diffAttrs); errTx != nil {
  541. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  542. }
  543. }
  544. return errTx
  545. }); err == nil {
  546. pkVal := r.getFieldValue(refModel, r.primaryKey)
  547. return httpCtx.Success(&UpdateResponse{
  548. ID: pkVal,
  549. Topic: r.model.TableName(),
  550. State: "updated",
  551. })
  552. }
  553. //form validation
  554. if validateError, ok := err.(*errpkg.StructError); ok {
  555. httpCtx.Response().Header().Set("Content-Type", "application/json")
  556. return json.NewEncoder(httpCtx.Response()).Encode(map[string]interface{}{
  557. "errno": HttpValidateFailed,
  558. "result": validateError,
  559. })
  560. }
  561. return httpCtx.Error(HttpDatabaseUpdateFailed, err.Error())
  562. }
  563. func (r *Restful) actionDelete(httpCtx *http.Context) (err error) {
  564. var (
  565. errTx error
  566. model interface{}
  567. namespace string
  568. )
  569. if !r.hasScenario(ScenarioDelete) {
  570. return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
  571. }
  572. ctx := r.createContext(httpCtx)
  573. idStr := httpCtx.ParamValue("id")
  574. namespace = httpCtx.ParamValue(NamespaceVariable)
  575. model = reflect.New(r.reflectType).Interface()
  576. conditions := map[string]interface{}{
  577. r.primaryKey: idStr,
  578. }
  579. if r.opts.EnableNamespace {
  580. conditions[NamespaceField] = namespace
  581. }
  582. if err = r.opts.DB.Where(conditions).First(model).Error; err != nil {
  583. return httpCtx.Error(HttpDatabaseFindFailed, err.Error())
  584. }
  585. if err = r.opts.DB.Transaction(func(tx *gorm.DB) error {
  586. if r.opts.Delegate != nil {
  587. if errTx = r.opts.Delegate.BeforeDelete(ctx, model); errTx != nil {
  588. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  589. }
  590. }
  591. if activeModel, ok := model.(ActiveModel); ok {
  592. if errTx = activeModel.OnBeforeDelete(ctx, model); errTx != nil {
  593. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  594. }
  595. }
  596. if errTx = tx.Delete(model).Error; errTx != nil {
  597. return errTx
  598. }
  599. if activeModel, ok := model.(ActiveModel); ok {
  600. if errTx = activeModel.OnAfterDelete(ctx, model); errTx != nil {
  601. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  602. }
  603. }
  604. if r.opts.Delegate != nil {
  605. if errTx = r.opts.Delegate.AfterDelete(ctx, model); errTx != nil {
  606. return httpCtx.Error(HttpRequestCallbackFailed, errTx.Error())
  607. }
  608. }
  609. return errTx
  610. }); err == nil {
  611. return httpCtx.Success(&DeleteResponse{
  612. ID: r.getFieldValue(reflect.ValueOf(model), r.primaryKey),
  613. Topic: r.model.TableName(),
  614. State: "updated",
  615. })
  616. } else {
  617. return httpCtx.Error(HttpDatabaseDeleteFailed, err.Error())
  618. }
  619. }
  620. func (r *Restful) actionExport(httpCtx *http.Context) (err error) {
  621. var (
  622. query *Query
  623. namespace string
  624. )
  625. if !r.hasScenario(ScenarioExport) {
  626. return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
  627. }
  628. ctx := r.createContext(httpCtx)
  629. namespace = httpCtx.ParamValue(NamespaceVariable)
  630. sliceValue := reflect.MakeSlice(reflect.SliceOf(r.reflectType), 0, 0)
  631. models := reflect.New(sliceValue.Type())
  632. models.Elem().Set(sliceValue)
  633. query = NewQuery(r.opts.DB)
  634. searchSchemas := r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioSearch)
  635. exportSchemas := r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioList)
  636. if err = r.prepareConditions(ctx, httpCtx, query, searchSchemas); err != nil {
  637. return httpCtx.Error(HttpDatabaseQueryFailed, err.Error())
  638. }
  639. if r.opts.EnableNamespace {
  640. query.AndFilterWhere(NewQueryCondition(NamespaceVariable, namespace))
  641. }
  642. if err = query.All(models.Interface()); err != nil {
  643. return httpCtx.Error(HttpDatabaseExportFailed, err.Error())
  644. }
  645. httpCtx.Response().Header().Set("Content-Type", "text/csv")
  646. httpCtx.Response().Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
  647. httpCtx.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=%s.csv", r.singularName))
  648. value := r.opts.Formatter.formatModels(ctx, models.Interface(), exportSchemas, r.statement)
  649. writer := csv.NewWriter(httpCtx.Response())
  650. ss := make([]string, len(exportSchemas))
  651. for i, field := range exportSchemas {
  652. ss[i] = field.Label
  653. }
  654. _ = writer.Write(ss)
  655. if values, ok := value.([]interface{}); ok {
  656. for _, val := range values {
  657. row, ok2 := val.(map[string]interface{})
  658. if !ok2 {
  659. continue
  660. }
  661. for i, field := range exportSchemas {
  662. if v, ok := row[field.Column]; ok {
  663. ss[i] = fmt.Sprint(v)
  664. } else {
  665. ss[i] = ""
  666. }
  667. }
  668. _ = writer.Write(ss)
  669. }
  670. }
  671. writer.Flush()
  672. return
  673. }
  674. func (r *Restful) actionView(httpCtx *http.Context) (err error) {
  675. var (
  676. model interface{}
  677. namespace string
  678. )
  679. if !r.hasScenario(ScenarioView) {
  680. return httpCtx.Error(HttpAccessDenied, ErrorAccessDeniedMessage)
  681. }
  682. ctx := r.createContext(httpCtx)
  683. namespace = httpCtx.ParamValue(NamespaceVariable)
  684. scenario := httpCtx.FormValue("scenario")
  685. idStr := httpCtx.ParamValue("id")
  686. model = reflect.New(r.reflectType).Interface()
  687. conditions := map[string]interface{}{
  688. r.primaryKey: idStr,
  689. }
  690. if r.opts.EnableNamespace {
  691. conditions[NamespaceField] = namespace
  692. }
  693. if err = r.opts.DB.Where(conditions).First(model).Error; err != nil {
  694. return httpCtx.Error(HttpDatabaseFindFailed, err.Error())
  695. }
  696. if httpCtx.FormValue("format") != "" {
  697. //获取指定场景下面的字段进行渲染显示
  698. var schemas []*Schema
  699. if scenario == "" {
  700. schemas = r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), ScenarioView)
  701. } else {
  702. schemas = r.opts.LookupFunc(ctx, namespace, r.model.ModuleName(), r.model.TableName(), scenario)
  703. }
  704. return httpCtx.Success(r.opts.Formatter.formatModel(ctx, model, schemas, r.statement))
  705. }
  706. return httpCtx.Success(model)
  707. }
  708. func newRestful(model Model, opts *Options) *Restful {
  709. var (
  710. ok bool
  711. err error
  712. tableName string
  713. dynamicModel *Dynamic
  714. )
  715. r := &Restful{
  716. opts: opts,
  717. model: model,
  718. }
  719. if dynamicModel, ok = model.(*Dynamic); ok {
  720. r.reflectValue = reflect.New(dynamicModel.Type()).Elem()
  721. r.reflectType = dynamicModel.Type()
  722. } else {
  723. r.reflectValue = reflect.Indirect(reflect.ValueOf(model))
  724. r.reflectType = r.reflectValue.Type()
  725. }
  726. tableName = model.TableName()
  727. r.singularName = inflector.Singularize(tableName)
  728. r.pluralizeName = inflector.Pluralize(tableName)
  729. r.statement = &gorm.Statement{
  730. DB: r.opts.DB,
  731. ConnPool: r.opts.DB.ConnPool,
  732. Clauses: map[string]clause.Clause{},
  733. }
  734. if dynamicModel, ok = model.(*Dynamic); ok {
  735. err = r.statement.Parse(dynamicModel.Interface())
  736. } else {
  737. err = r.statement.Parse(model)
  738. }
  739. if err == nil {
  740. if r.statement.Schema != nil {
  741. if r.statement.Schema.PrimaryFieldDBNames != nil && len(r.statement.Schema.PrimaryFieldDBNames) > 0 {
  742. r.primaryKey = r.statement.Schema.PrimaryFieldDBNames[0]
  743. }
  744. }
  745. }
  746. return r
  747. }