rest.go 23 KB

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