dispatcher.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package dispatcher
  15. import (
  16. "context"
  17. "fmt"
  18. "net/http"
  19. "strings"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/appctx"
  23. "yunion.io/x/pkg/utils"
  24. "yunion.io/x/onecloud/pkg/appsrv"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  26. "yunion.io/x/onecloud/pkg/httperrors"
  27. "yunion.io/x/onecloud/pkg/mcclient/modulebase"
  28. )
  29. func AddModelDispatcher(prefix string, app *appsrv.Application, manager IModelDispatchHandler, isSlave bool) {
  30. metadata := map[string]interface{}{"manager": manager}
  31. tags := map[string]string{"resource": manager.KeywordPlural()}
  32. // list
  33. h := app.AddHandler2("GET",
  34. fmt.Sprintf("%s/%s", prefix, manager.KeywordPlural()),
  35. manager.Filter(listHandler), metadata, "list", tags)
  36. manager.CustomizeHandlerInfo(h)
  37. ctxss := manager.ContextKeywordPlurals()
  38. // list in context
  39. for _, ctxs := range ctxss {
  40. segs := make([]string, 0)
  41. segs = append(segs, prefix)
  42. for i, ctx := range ctxs {
  43. segs = append(segs, ctx, fmt.Sprintf("<resid_%d>", i))
  44. }
  45. segs = append(segs, manager.KeywordPlural())
  46. h = app.AddHandler2("GET", strings.Join(segs, "/"),
  47. manager.Filter(listInContextHandler), metadata, fmt.Sprintf("list_in_%s", strings.Join(ctxs, "_")), tags)
  48. manager.CustomizeHandlerInfo(h)
  49. }
  50. // Head
  51. h = app.AddHandler2("HEAD",
  52. fmt.Sprintf("%s/%s/<resid>", prefix, manager.KeywordPlural()),
  53. manager.Filter(headHandler), metadata, "head_details", tags)
  54. manager.CustomizeHandlerInfo(h)
  55. // Get
  56. h = app.AddHandler2("GET",
  57. fmt.Sprintf("%s/%s/<resid>", prefix, manager.KeywordPlural()),
  58. manager.Filter(getHandler), metadata, "get_details", tags)
  59. manager.CustomizeHandlerInfo(h)
  60. // get spec
  61. h = app.AddHandler2("GET",
  62. fmt.Sprintf("%s/%s/<resid>/<spec>", prefix, manager.KeywordPlural()),
  63. manager.Filter(getSpecHandler), metadata, "get_specific", tags)
  64. manager.CustomizeHandlerInfo(h)
  65. if isSlave {
  66. // slave node only support get and head
  67. return
  68. }
  69. // create
  70. // create multi
  71. h = app.AddHandler2("POST",
  72. fmt.Sprintf("%s/%s", prefix, manager.KeywordPlural()),
  73. manager.Filter(createHandler), metadata, "create", tags)
  74. manager.CustomizeHandlerInfo(h)
  75. // create in context
  76. for _, ctxs := range ctxss {
  77. segs := make([]string, 0)
  78. segs = append(segs, prefix)
  79. for i, ctx := range ctxs {
  80. segs = append(segs, ctx, fmt.Sprintf("<resid_%d>", i))
  81. }
  82. segs = append(segs, manager.KeywordPlural())
  83. h = app.AddHandler2("POST", strings.Join(segs, "/"),
  84. manager.Filter(createInContextHandler), metadata, fmt.Sprintf("create_in_%s", strings.Join(ctxs, "_")), tags)
  85. manager.CustomizeHandlerInfo(h)
  86. }
  87. // batchPerformAction
  88. h = app.AddHandler2("POST",
  89. fmt.Sprintf("%s/%s/<action>", prefix, manager.KeywordPlural()),
  90. manager.Filter(performClassActionHandler), metadata, "perform_class_action", tags)
  91. manager.CustomizeHandlerInfo(h)
  92. // performAction
  93. h = app.AddHandler2("POST",
  94. fmt.Sprintf("%s/%s/<resid>/<action>", prefix, manager.KeywordPlural()),
  95. manager.Filter(performActionHandler), metadata, "perform_action", tags)
  96. manager.CustomizeHandlerInfo(h)
  97. // batchUpdate
  98. /* app.AddHandler2("PUT",
  99. fmt.Sprintf("%s/%s", prefix, manager.KeywordPlural()),
  100. manager.Filter(updateClassHandler), metadata, "update_class", tags)
  101. */
  102. // update
  103. h = app.AddHandler2("PUT",
  104. fmt.Sprintf("%s/%s/<resid>", prefix, manager.KeywordPlural()),
  105. manager.Filter(updateHandler), metadata, "update", tags)
  106. manager.CustomizeHandlerInfo(h)
  107. // patch
  108. h = app.AddHandler2("PATCH",
  109. fmt.Sprintf("%s/%s/<resid>", prefix, manager.KeywordPlural()),
  110. manager.Filter(updateHandler), metadata, "patch", tags)
  111. manager.CustomizeHandlerInfo(h)
  112. // update/patch in context
  113. for _, ctxs := range ctxss {
  114. segs := make([]string, 0)
  115. segs = append(segs, prefix)
  116. for i, ctx := range ctxs {
  117. segs = append(segs, ctx, fmt.Sprintf("<resid_%d>", i))
  118. }
  119. segs = append(segs, manager.KeywordPlural(), "<resid>")
  120. h = app.AddHandler2("PUT", strings.Join(segs, "/"),
  121. manager.Filter(updateInContextHandler), metadata, fmt.Sprintf("update_in_%s", strings.Join(ctxs, "_")), tags)
  122. manager.CustomizeHandlerInfo(h)
  123. h = app.AddHandler2("PATCH", strings.Join(segs, "/"),
  124. manager.Filter(updateInContextHandler), metadata, fmt.Sprintf("patch_in_%s", strings.Join(ctxs, "_")), tags)
  125. manager.CustomizeHandlerInfo(h)
  126. }
  127. // update spec
  128. h = app.AddHandler2("PUT",
  129. fmt.Sprintf("%s/%s/<resid>/<spec>", prefix, manager.KeywordPlural()),
  130. manager.Filter(updateSpecHandler), metadata, "update_spec", tags)
  131. manager.CustomizeHandlerInfo(h)
  132. // patch spec
  133. h = app.AddHandler2("PATCH",
  134. fmt.Sprintf("%s/%s/<resid>/<spec>", prefix, manager.KeywordPlural()),
  135. manager.Filter(updateSpecHandler), metadata, "patch_spec", tags)
  136. manager.CustomizeHandlerInfo(h)
  137. // batch Delete
  138. /* app.AddHandler2("DELTE",
  139. fmt.Sprintf("%s/%s", prefix, manager.KeywordPlural()),
  140. manager.Filter(batachDeleteHandler), metadata, "batch_delete", tags)
  141. */
  142. // Delete
  143. h = app.AddHandler2("DELETE",
  144. fmt.Sprintf("%s/%s/<resid>", prefix, manager.KeywordPlural()),
  145. manager.Filter(deleteHandler), metadata, "delete", tags)
  146. manager.CustomizeHandlerInfo(h)
  147. // delete in context
  148. for _, ctxs := range ctxss {
  149. segs := make([]string, 0)
  150. segs = append(segs, prefix)
  151. for i, ctx := range ctxs {
  152. segs = append(segs, ctx, fmt.Sprintf("<resid_%d>", i))
  153. }
  154. segs = append(segs, manager.KeywordPlural(), "<resid>")
  155. h = app.AddHandler2("DELETE", strings.Join(segs, "/"),
  156. manager.Filter(deleteInContextHandler), metadata, fmt.Sprintf("delete_in_%s", strings.Join(ctxs, "_")), tags)
  157. manager.CustomizeHandlerInfo(h)
  158. }
  159. // Delete Spec
  160. h = app.AddHandler2("DELETE",
  161. fmt.Sprintf("%s/%s/<resid>/<spec>", prefix, manager.KeywordPlural()),
  162. manager.Filter(deleteSpecHandler), metadata, "delete_spec", tags)
  163. manager.CustomizeHandlerInfo(h)
  164. }
  165. func fetchEnv(ctx context.Context, w http.ResponseWriter, r *http.Request) (IModelDispatchHandler, map[string]string, jsonutils.JSONObject, jsonutils.JSONObject) {
  166. params, query, body := appsrv.FetchEnv(ctx, w, r)
  167. metadata := appctx.AppContextMetadata(ctx)
  168. manager, ok := metadata["manager"].(IModelDispatchHandler)
  169. if !ok {
  170. log.Fatalf("No manager found for URL: %s", r.URL)
  171. }
  172. return manager, params, query, body
  173. }
  174. func mergeQueryParams(params map[string]string, query jsonutils.JSONObject, excludes ...string) jsonutils.JSONObject {
  175. if query == nil {
  176. query = jsonutils.NewDict()
  177. }
  178. queryDict := query.(*jsonutils.JSONDict)
  179. for k, v := range params {
  180. if !utils.IsInStringArray(k, excludes) {
  181. queryDict.Add(jsonutils.NewString(v), k[1:len(k)-1])
  182. }
  183. }
  184. return queryDict
  185. }
  186. func listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  187. manager, params, query, _ := fetchEnv(ctx, w, r)
  188. handleList(ctx, w, manager, nil, mergeQueryParams(params, query))
  189. }
  190. func handleList(ctx context.Context, w http.ResponseWriter, manager IModelDispatchHandler, ctxIds []SResourceContext, query jsonutils.JSONObject) {
  191. listResult, err := manager.List(ctx, query, ctxIds)
  192. if err != nil {
  193. httperrors.GeneralServerError(ctx, w, err)
  194. return
  195. }
  196. key := manager.KeywordPlural()
  197. if consts.GetDataResp() {
  198. key = "data"
  199. }
  200. appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, key))
  201. }
  202. func fetchContextIds(segs []string, params map[string]string) ([]SResourceContext, []string) {
  203. ctxIds := make([]SResourceContext, 0)
  204. keys := make([]string, 0)
  205. idx := 0
  206. key := fmt.Sprintf("<resid_%d>", idx)
  207. for i := 0; i < len(segs); i += 1 {
  208. if segs[i] == key {
  209. ctxIds = append(ctxIds, SResourceContext{Type: segs[i-1], Id: params[key]})
  210. keys = append(keys, key)
  211. idx += 1
  212. key = fmt.Sprintf("<resid_%d>", idx)
  213. }
  214. }
  215. return ctxIds, keys
  216. }
  217. func listInContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  218. manager, params, query, _ := fetchEnv(ctx, w, r)
  219. ctxIds, ctxKeys := fetchContextIds(appctx.AppContextCurrentRoot(ctx), params)
  220. handleList(ctx, w, manager, ctxIds, mergeQueryParams(params, query, ctxKeys...))
  221. }
  222. func wrapBody(body jsonutils.JSONObject, key string) jsonutils.JSONObject {
  223. if body != nil {
  224. ret := jsonutils.NewDict()
  225. ret.Add(body, key)
  226. return ret
  227. } else {
  228. return nil
  229. }
  230. }
  231. func headHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  232. defer func() {
  233. w.Header().Set("Content-Length", "0")
  234. w.Write([]byte{})
  235. }()
  236. manager, params, query, _ := fetchEnv(ctx, w, r)
  237. _, err := manager.Get(ctx, params["<resid>"], mergeQueryParams(params, query, "<resid>"), true)
  238. if err != nil {
  239. jsonErr := httperrors.NewGeneralError(err)
  240. httperrors.SendHTTPErrorHeader(w, jsonErr.Code)
  241. return
  242. }
  243. }
  244. func sendJSON(ctx context.Context, w http.ResponseWriter, result jsonutils.JSONObject, keyword string) {
  245. appParams := appsrv.AppContextGetParams(ctx)
  246. var body jsonutils.JSONObject
  247. if consts.GetDataResp() || appParams != nil && appParams.OverrideResponseBodyWrapper {
  248. body = result
  249. } else {
  250. body = wrapBody(result, keyword)
  251. }
  252. appsrv.SendJSON(w, body)
  253. }
  254. func getHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  255. manager, params, query, _ := fetchEnv(ctx, w, r)
  256. result, err := manager.Get(ctx, params["<resid>"], mergeQueryParams(params, query, "<resid>"), false)
  257. if err != nil {
  258. e := httperrors.NewGeneralError(err)
  259. httperrors.JsonClientError(ctx, w, e)
  260. return
  261. }
  262. if result != nil {
  263. sendJSON(ctx, w, result, manager.Keyword())
  264. }
  265. }
  266. func getSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  267. manager, params, query, _ := fetchEnv(ctx, w, r)
  268. result, err := manager.GetSpecific(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"))
  269. if err != nil {
  270. e := httperrors.NewGeneralError(err)
  271. httperrors.JsonClientError(ctx, w, e)
  272. return
  273. }
  274. if result != nil {
  275. sendJSON(ctx, w, result, manager.Keyword())
  276. }
  277. }
  278. func writeErrNoRequestKey(ctx context.Context, w http.ResponseWriter, r *http.Request, key string) {
  279. ctx = appctx.WithRequestLang(ctx, r)
  280. httperrors.InvalidInputError(ctx, w,
  281. "No request key: %s", key)
  282. }
  283. func writeErrInvalidRequestHeader(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) {
  284. ctx = appctx.WithRequestLang(ctx, r)
  285. httperrors.InvalidInputError(ctx, w,
  286. "Invalid request header: %v", err)
  287. }
  288. func createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  289. manager, params, query, body := fetchEnv(ctx, w, r)
  290. handleCreate(ctx, w, manager, nil, mergeQueryParams(params, query), body, r)
  291. }
  292. func handleCreate(ctx context.Context, w http.ResponseWriter, manager IModelDispatchHandler, ctxIds []SResourceContext, query jsonutils.JSONObject, body jsonutils.JSONObject, r *http.Request) {
  293. count := int64(1)
  294. var data jsonutils.JSONObject
  295. var err error
  296. if body != nil {
  297. count, _ = body.Int("count")
  298. data, err = body.Get(manager.Keyword())
  299. if err != nil {
  300. writeErrNoRequestKey(ctx, w, r, manager.Keyword())
  301. return
  302. }
  303. } else {
  304. data, err = manager.FetchCreateHeaderData(ctx, r.Header)
  305. if err != nil {
  306. writeErrInvalidRequestHeader(ctx, w, r, err)
  307. return
  308. }
  309. }
  310. if count <= 1 {
  311. result, err := manager.Create(ctx, query, data, ctxIds)
  312. if err != nil {
  313. httperrors.GeneralServerError(ctx, w, err)
  314. return
  315. }
  316. if !consts.GetDataResp() {
  317. result = wrapBody(result, manager.Keyword())
  318. }
  319. appsrv.SendJSON(w, result)
  320. } else {
  321. results, err := manager.BatchCreate(ctx, query, data, int(count), ctxIds)
  322. if err != nil {
  323. httperrors.GeneralServerError(ctx, w, err)
  324. return
  325. }
  326. ret := jsonutils.NewArray()
  327. for i := 0; i < len(results); i++ {
  328. res := jsonutils.NewDict()
  329. res.Add(jsonutils.NewInt(int64(results[i].Status)), "status")
  330. res.Add(results[i].Data, "body")
  331. ret.Add(res)
  332. }
  333. key := manager.KeywordPlural()
  334. if consts.GetDataResp() {
  335. key = "data"
  336. }
  337. appsrv.SendJSON(w, wrapBody(ret, key))
  338. }
  339. }
  340. func createInContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  341. manager, params, query, body := fetchEnv(ctx, w, r)
  342. ctxIds, ctxKeys := fetchContextIds(appctx.AppContextCurrentRoot(ctx), params)
  343. handleCreate(ctx, w, manager, ctxIds, mergeQueryParams(params, query, ctxKeys...), body, r)
  344. }
  345. func performClassActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  346. manager, params, query, body := fetchEnv(ctx, w, r)
  347. var data jsonutils.JSONObject
  348. if body != nil {
  349. if body.Contains(manager.KeywordPlural()) {
  350. data, _ = body.Get(manager.KeywordPlural())
  351. if data == nil {
  352. data = body.(*jsonutils.JSONDict)
  353. }
  354. } else {
  355. data = body
  356. }
  357. } else {
  358. data = jsonutils.NewDict()
  359. }
  360. results, err := manager.PerformClassAction(ctx, params["<action>"], mergeQueryParams(params, query, "<action>"), data)
  361. if err != nil {
  362. httperrors.GeneralServerError(ctx, w, err)
  363. return
  364. }
  365. if results == nil {
  366. results = jsonutils.NewDict()
  367. }
  368. sendJSON(ctx, w, results, manager.KeywordPlural())
  369. // appsrv.SendJSON(w, wrapBody(results, manager.KeywordPlural()))
  370. }
  371. func performActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  372. manager, params, query, body := fetchEnv(ctx, w, r)
  373. var data jsonutils.JSONObject
  374. if body != nil {
  375. if body.Contains(manager.Keyword()) {
  376. data, _ = body.Get(manager.Keyword())
  377. if data == nil {
  378. data = body.(*jsonutils.JSONDict)
  379. }
  380. } else {
  381. data = body
  382. }
  383. } else {
  384. data = jsonutils.NewDict()
  385. }
  386. result, err := manager.PerformAction(ctx, params["<resid>"], params["<action>"], mergeQueryParams(params, query, "<resid>", "<action>"), data)
  387. if err != nil {
  388. httperrors.GeneralServerError(ctx, w, err)
  389. return
  390. }
  391. sendJSON(ctx, w, result, manager.Keyword())
  392. // appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
  393. }
  394. func updateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  395. manager, params, query, body := fetchEnv(ctx, w, r)
  396. handleUpdate(ctx, w, manager, params["<resid>"], nil, mergeQueryParams(params, query, "<resid>"), body, r)
  397. }
  398. func handleUpdate(ctx context.Context, w http.ResponseWriter, manager IModelDispatchHandler, resId string, ctxIds []SResourceContext, query jsonutils.JSONObject, body jsonutils.JSONObject, r *http.Request) {
  399. var data jsonutils.JSONObject
  400. var err error
  401. if body != nil {
  402. if body.Contains(manager.Keyword()) {
  403. data, err = body.Get(manager.Keyword())
  404. if err != nil {
  405. writeErrNoRequestKey(ctx, w, r, manager.Keyword())
  406. return
  407. }
  408. } else {
  409. data = body
  410. }
  411. } else {
  412. data, err = manager.FetchUpdateHeaderData(ctx, r.Header)
  413. if err != nil {
  414. writeErrInvalidRequestHeader(ctx, w, r, err)
  415. return
  416. }
  417. }
  418. result, err := manager.Update(ctx, resId, query, data, ctxIds)
  419. if err != nil {
  420. httperrors.GeneralServerError(ctx, w, err)
  421. return
  422. }
  423. sendJSON(ctx, w, result, manager.Keyword())
  424. // appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
  425. }
  426. func updateInContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  427. manager, params, query, body := fetchEnv(ctx, w, r)
  428. ctxIds, ctxKeys := fetchContextIds(appctx.AppContextCurrentRoot(ctx), params)
  429. ctxKeys = append(ctxKeys, "<resid>")
  430. handleUpdate(ctx, w, manager, params["<resid>"], ctxIds, mergeQueryParams(params, query, ctxKeys...), body, r)
  431. }
  432. func updateSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  433. manager, params, query, body := fetchEnv(ctx, w, r)
  434. var data jsonutils.JSONObject
  435. var err error
  436. if body != nil {
  437. if body.Contains(manager.Keyword()) {
  438. data, err = body.Get(manager.Keyword())
  439. if err != nil {
  440. writeErrNoRequestKey(ctx, w, r, manager.Keyword())
  441. return
  442. }
  443. } else {
  444. data = body
  445. }
  446. } else {
  447. data, err = manager.FetchUpdateHeaderData(ctx, r.Header)
  448. if err != nil {
  449. writeErrInvalidRequestHeader(ctx, w, r, err)
  450. return
  451. }
  452. }
  453. result, err := manager.UpdateSpec(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"), data)
  454. if err != nil {
  455. httperrors.GeneralServerError(ctx, w, err)
  456. return
  457. }
  458. sendJSON(ctx, w, result, manager.Keyword())
  459. // appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
  460. }
  461. func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  462. manager, params, query, body := fetchEnv(ctx, w, r)
  463. handleDelete(ctx, w, manager, params["<resid>"], nil, mergeQueryParams(params, query, "<resid>"), body, r)
  464. }
  465. func handleDelete(ctx context.Context, w http.ResponseWriter, manager IModelDispatchHandler, resId string, ctxIds []SResourceContext, query jsonutils.JSONObject, body jsonutils.JSONObject, r *http.Request) {
  466. var data jsonutils.JSONObject
  467. var err error
  468. if body != nil {
  469. if body.Contains(manager.Keyword()) {
  470. data, err = body.Get(manager.Keyword())
  471. if err != nil {
  472. writeErrNoRequestKey(ctx, w, r, manager.Keyword())
  473. return
  474. }
  475. } else {
  476. data = body
  477. }
  478. } else {
  479. data = jsonutils.NewDict()
  480. }
  481. // doDelete
  482. result, err := manager.Delete(ctx, resId, query, data, ctxIds)
  483. if err != nil {
  484. httperrors.GeneralServerError(ctx, w, err)
  485. return
  486. }
  487. sendJSON(ctx, w, result, manager.Keyword())
  488. // appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
  489. }
  490. func deleteInContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  491. manager, params, query, body := fetchEnv(ctx, w, r)
  492. ctxIds, ctxKeys := fetchContextIds(appctx.AppContextCurrentRoot(ctx), params)
  493. ctxKeys = append(ctxKeys, "<resid>")
  494. handleDelete(ctx, w, manager, params["<resid>"], ctxIds, mergeQueryParams(params, query, ctxKeys...), body, r)
  495. }
  496. func deleteSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  497. manager, params, query, body := fetchEnv(ctx, w, r)
  498. var data jsonutils.JSONObject
  499. var err error
  500. if body != nil {
  501. if body.Contains(manager.Keyword()) {
  502. data, err = body.Get(manager.Keyword())
  503. if err != nil {
  504. writeErrNoRequestKey(ctx, w, r, manager.Keyword())
  505. return
  506. }
  507. } else {
  508. data = body
  509. }
  510. } else {
  511. data = jsonutils.NewDict()
  512. }
  513. result, err := manager.DeleteSpec(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"), data)
  514. if err != nil {
  515. httperrors.GeneralServerError(ctx, w, err)
  516. return
  517. }
  518. sendJSON(ctx, w, result, manager.Keyword())
  519. // appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
  520. }