resource.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  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 handler
  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/util/printutils"
  23. "yunion.io/x/pkg/utils"
  24. "yunion.io/x/onecloud/pkg/appsrv"
  25. "yunion.io/x/onecloud/pkg/httperrors"
  26. "yunion.io/x/onecloud/pkg/mcclient"
  27. "yunion.io/x/onecloud/pkg/mcclient/modulebase"
  28. "yunion.io/x/onecloud/pkg/util/excelutils"
  29. )
  30. const (
  31. APIVer = "<apiver>"
  32. ResName = "<resname>"
  33. ResID = "<resid>"
  34. ResName2 = "<resname2>"
  35. ResID2 = "<resid2>"
  36. ResName3 = "<resname3>"
  37. ResID3 = "<resid3>"
  38. Spec = "<spec>"
  39. Action = "<action>"
  40. GET = "GET"
  41. PUT = "PUT"
  42. POST = "POST"
  43. DELETE = "DELETE"
  44. PATCH = "PATCH"
  45. )
  46. type ResourceHandlers struct {
  47. *SHandlers
  48. }
  49. func NewResourceHandlers(prefix string) *ResourceHandlers {
  50. return &ResourceHandlers{NewHandlers(prefix)}
  51. }
  52. func (f *ResourceHandlers) AddGet(mf appsrv.MiddlewareFunc) *ResourceHandlers {
  53. hs := []HandlerPath{
  54. // list and joint list
  55. NewHP(f.listHandler, APIVer, ResName),
  56. // get
  57. NewHP(f.getHandler, APIVer, ResName, ResID),
  58. // get spec, list in context, joint list descendent
  59. NewHP(f.getSpecHandler, APIVer, ResName, ResID, Spec),
  60. // joint get
  61. NewHP(f.getJointHandler, APIVer, ResName, ResID, ResName2, ResID2),
  62. // list in 2 context
  63. NewHP(f.listInContextsHandler, APIVer, ResName, ResID, ResName2, ResID2, ResName3),
  64. }
  65. f.AddByMethod(GET, mf, hs...)
  66. return f
  67. }
  68. func (f *ResourceHandlers) AddPost(mf appsrv.MiddlewareFunc) *ResourceHandlers {
  69. hs := []HandlerPath{
  70. // create, create multi
  71. NewHP(f.createHandler, APIVer, ResName),
  72. // batch performAction
  73. NewHP(f.batchPerformActionHandler, APIVer, ResName, Action),
  74. // performAction, create in context, batchAttach
  75. NewHP(f.performActionHandler, APIVer, ResName, ResID, Action),
  76. // joint attach
  77. NewHP(f.attachHandler, APIVer, ResName, ResID, ResName2, ResID2),
  78. }
  79. f.AddByMethod(POST, mf, hs...)
  80. return f
  81. }
  82. func (f *ResourceHandlers) AddPut(mf appsrv.MiddlewareFunc) *ResourceHandlers {
  83. hs := []HandlerPath{
  84. // batchPut
  85. NewHP(f.batchUpdateHandler, APIVer, ResName),
  86. // put
  87. NewHP(f.updateHandler, APIVer, ResName, ResID),
  88. // batchPut joint
  89. NewHP(f.batchUpdateJointHandler, APIVer, ResName, ResID, ResName2),
  90. // update joint, update in context
  91. NewHP(f.updateJointHandler, APIVer, ResName, ResID, ResName2, ResID2),
  92. // update in contexts
  93. NewHP(f.updateInContextsHandler, APIVer, ResName, ResID, ResName2, ResID2, ResName3, ResID3),
  94. }
  95. f.AddByMethod(PUT, mf, hs...)
  96. return f
  97. }
  98. func (f *ResourceHandlers) AddPatch(mf appsrv.MiddlewareFunc) *ResourceHandlers {
  99. hs := []HandlerPath{
  100. // batchPatch
  101. NewHP(f.batchPatchHandler, APIVer, ResName),
  102. // patch
  103. NewHP(f.patchHandler, APIVer, ResName, ResID),
  104. // patch joint, patch in context
  105. NewHP(f.patchJointHandler, APIVer, ResName, ResID, ResName2, ResID2),
  106. // patch in contexts
  107. NewHP(f.patchInContextsHandler, APIVer, ResName, ResID, ResName2, ResID2, ResName3, ResID3),
  108. }
  109. f.AddByMethod(PATCH, mf, hs...)
  110. return f
  111. }
  112. func (f *ResourceHandlers) AddDelete(mf appsrv.MiddlewareFunc) *ResourceHandlers {
  113. hs := []HandlerPath{
  114. // batchDelete
  115. NewHP(f.batchDeleteHandler, APIVer, ResName),
  116. // delete
  117. NewHP(f.deleteHandler, APIVer, ResName, ResID),
  118. // batch detach
  119. NewHP(f.batchDetachHandler, APIVer, ResName, ResID, ResName2),
  120. // detach joint, delete in context
  121. NewHP(f.detachHandle, APIVer, ResName, ResID, ResName2, ResID2),
  122. // list in 2 context
  123. NewHP(f.deleteInContextsHandler, APIVer, ResName, ResID, ResName2, ResID2, ResName3, ResID3),
  124. }
  125. f.AddByMethod(DELETE, mf, hs...)
  126. return f
  127. }
  128. func fetchIdList(ctx context.Context, query jsonutils.JSONObject, w http.ResponseWriter) []string {
  129. idlist, e := query.GetArray("id")
  130. if e == nil && len(idlist) > 0 {
  131. queryDict := query.(*jsonutils.JSONDict)
  132. queryDict.Remove("id")
  133. log.Debugf("Get id list: %s", idlist)
  134. return jsonutils.JSONArray2StringArray(idlist)
  135. } else {
  136. log.Debugf("Cannot find id list in query: %s", query)
  137. httperrors.InvalidInputError(ctx, w, "No id list found")
  138. return nil
  139. }
  140. }
  141. // list
  142. // joint list
  143. // /<resname>
  144. func (f *ResourceHandlers) listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  145. req := newRequest(ctx, w, r)
  146. if req.Error() != nil {
  147. httperrors.GeneralServerError(ctx, w, req.Error())
  148. return
  149. }
  150. jmod, _ := modulebase.GetJointModule(req.Session(), req.ResName())
  151. if jmod != nil {
  152. f.doList(ctx, req.Session(), jmod, req.Query(), w, r)
  153. return
  154. }
  155. if err := req.WithMod1().Error(); err != nil {
  156. httperrors.GeneralServerError(ctx, w, err)
  157. return
  158. }
  159. batchGet, err := req.Query().Bool("batchGet")
  160. if err == nil && batchGet {
  161. idlist := fetchIdList(ctx, req.Query(), w)
  162. if idlist == nil {
  163. return
  164. }
  165. querydict, ok := req.Query().(*jsonutils.JSONDict)
  166. if ok {
  167. querydict.Remove("batchGet")
  168. querydict.Remove("id")
  169. }
  170. ret := req.Mod1().BatchGet(req.Session(), idlist, req.Query())
  171. appsrv.SendJSON(w, modulebase.ListResult2JSON(modulebase.SubmitResults2ListResult(ret)))
  172. return
  173. }
  174. f.doList(ctx, req.Session(), req.Mod1(), req.Query(), w, r)
  175. }
  176. type sExport struct {
  177. ExportFormat string `json:"export"`
  178. ExportFileName string `json:"export_file_name"`
  179. ExportKeys string `json:"export_keys"`
  180. ExportTexts string `json:"export_texts"`
  181. Keys []string
  182. Texts []string
  183. }
  184. func (f *ResourceHandlers) fetchExportQuery(query jsonutils.JSONObject) (jsonutils.JSONObject, sExport, error) {
  185. export := sExport{}
  186. query.Unmarshal(&export)
  187. export.Keys, export.Texts = []string{}, []string{}
  188. if len(export.ExportFormat) > 0 {
  189. if len(export.ExportKeys) > 0 {
  190. export.Keys = strings.Split(export.ExportKeys, ",")
  191. }
  192. if len(export.ExportTexts) > 0 {
  193. export.Texts = strings.Split(export.ExportTexts, ",")
  194. }
  195. if len(export.Keys) == 0 {
  196. return nil, export, fmt.Errorf("missing export keys")
  197. }
  198. if len(export.Texts) == 0 {
  199. export.Texts = export.Keys
  200. }
  201. if len(export.Keys) != len(export.Texts) {
  202. return nil, export, fmt.Errorf("inconsistent export keys and texts") // httperrors.InvalidInputError(ctx, w, "inconsistent export keys and texts")
  203. }
  204. queryDict := query.(*jsonutils.JSONDict)
  205. queryDict.Remove("export")
  206. queryDict.Remove("export_texts")
  207. queryDict.Remove("export_file_name")
  208. keys := []string{}
  209. for _, key := range export.Keys {
  210. if !strings.Contains(key, ".") {
  211. keys = append(keys, key)
  212. continue
  213. }
  214. key = strings.Split(key, ".")[0]
  215. if !utils.IsInStringArray(key, keys) {
  216. keys = append(keys, key)
  217. }
  218. }
  219. queryDict.Set("export_keys", jsonutils.NewString(strings.Join(keys, ",")))
  220. query = queryDict
  221. }
  222. return query, export, nil
  223. }
  224. func (f *ResourceHandlers) doList(ctx context.Context, session *mcclient.ClientSession, module modulebase.IBaseManager, query jsonutils.JSONObject, w http.ResponseWriter, r *http.Request) {
  225. query, export, err := f.fetchExportQuery(query)
  226. if err != nil {
  227. httperrors.InvalidInputError(ctx, w, "%s", err.Error())
  228. return
  229. }
  230. ret, e := module.List(session, query)
  231. if e != nil {
  232. httperrors.GeneralServerError(ctx, w, e)
  233. return
  234. }
  235. if len(export.ExportFormat) > 0 {
  236. w.Header().Set("Content-Description", "File Transfer")
  237. w.Header().Set("Content-Transfer-Encoding", "binary")
  238. w.Header().Set("Content-Type", "application/octet-stream")
  239. fileName := fmt.Sprintf("export-%s", module.KeyString())
  240. if len(export.ExportFileName) > 0 {
  241. fileName = export.ExportFileName
  242. }
  243. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.xlsx\"", fileName))
  244. excelutils.Export(ret.Data, export.Keys, export.Texts, w)
  245. return
  246. }
  247. appsrv.SendJSON(w, modulebase.ListResult2JSON(ret))
  248. }
  249. // get single
  250. // /<resname>/<resid>
  251. func (f *ResourceHandlers) getHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  252. req := newRequest(ctx, w, r).WithMod1()
  253. if err := req.Error(); err != nil {
  254. httperrors.GeneralServerError(ctx, w, err)
  255. return
  256. }
  257. obj, e := req.Mod1().Get(req.Session(), req.ResID(), req.Query())
  258. if e != nil {
  259. httperrors.GeneralServerError(ctx, w, e)
  260. return
  261. }
  262. if req.ResID() == "splitable-export" {
  263. if exports, ok := obj.(*jsonutils.JSONArray); ok && exports.Length() > 0 {
  264. data, _ := exports.GetArray()
  265. keys := data[0].(*jsonutils.JSONDict).SortedKeys()
  266. w.Header().Set("Content-Description", "File Transfer")
  267. w.Header().Set("Content-Transfer-Encoding", "binary")
  268. w.Header().Set("Content-Type", "application/octet-stream")
  269. fileName := fmt.Sprintf("export-%s", req.Mod1().KeyString())
  270. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.xlsx\"", fileName))
  271. excelutils.Export(data, keys, keys, w)
  272. return
  273. }
  274. }
  275. appsrv.SendJSON(w, obj)
  276. }
  277. // * get spec
  278. // * list in context
  279. // * joint list descendent
  280. // /<resname>/<resid>/<spec>
  281. // /<resname>/<resid>/<resname2>
  282. func (f *ResourceHandlers) getSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  283. req := newRequest(ctx, w, r).WithMod1()
  284. if err := req.Error(); err != nil {
  285. httperrors.GeneralServerError(ctx, w, err)
  286. return
  287. }
  288. session := req.Session()
  289. module := req.Mod1()
  290. query := req.Query()
  291. module2, e := modulebase.GetModule(session, req.Spec())
  292. if e != nil || module.GetSpecificMethods().Has(req.Spec()) {
  293. obj, e := module.GetSpecific(session, req.ResID(), req.Spec(), query)
  294. if e != nil {
  295. httperrors.GeneralServerError(ctx, w, e)
  296. return
  297. }
  298. appsrv.SendJSON(w, obj)
  299. return
  300. }
  301. // list in 1 context
  302. query, export, err := f.fetchExportQuery(query)
  303. if err != nil {
  304. httperrors.InvalidInputError(ctx, w, "%s", err.Error())
  305. return
  306. }
  307. jmod, e := modulebase.GetJointModule2(session, module, module2)
  308. var ret *printutils.ListResult
  309. if e == nil { // joint module
  310. ret, e = jmod.ListDescendent(session, req.ResID(), query)
  311. } else {
  312. ret, e = module2.ListInContext(session, query, module, req.ResID())
  313. }
  314. if e != nil {
  315. httperrors.GeneralServerError(ctx, w, e)
  316. return
  317. }
  318. if len(export.ExportFormat) > 0 {
  319. w.Header().Set("Content-Description", "File Transfer")
  320. w.Header().Set("Content-Transfer-Encoding", "binary")
  321. w.Header().Set("Content-Type", "application/octet-stream")
  322. fileName := fmt.Sprintf("export-%s", module.KeyString())
  323. if len(export.ExportFileName) > 0 {
  324. fileName = export.ExportFileName
  325. }
  326. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.xlsx\"", fileName))
  327. excelutils.Export(ret.Data, export.Keys, export.Texts, w)
  328. return
  329. }
  330. appsrv.SendJSON(w, modulebase.ListResult2JSON(ret))
  331. }
  332. // joint get
  333. // /<resname>/<resid>/<resname2>/<resid2>
  334. func (f *ResourceHandlers) getJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  335. req := newRequest(ctx, w, r).WithMod1().WithMod2()
  336. if err := req.Error(); err != nil {
  337. httperrors.GeneralServerError(ctx, w, err)
  338. return
  339. }
  340. module := req.Mod1()
  341. module2 := req.Mod2()
  342. session := req.Session()
  343. jmod, e := modulebase.GetJointModule2(session, module, module2)
  344. if e != nil {
  345. httperrors.NotFoundError(ctx, w, "resource %s-%s not exist", req.ResName(), req.ResName2())
  346. return
  347. }
  348. obj, e := jmod.Get(session, req.ResID(), req.ResID2(), req.Query())
  349. if e != nil {
  350. httperrors.GeneralServerError(ctx, w, e)
  351. } else {
  352. appsrv.SendJSON(w, obj)
  353. }
  354. }
  355. // list in 2 context
  356. // /<resname>/<resid>/<resname2>/<resid2>/<resnam3>
  357. func (f *ResourceHandlers) listInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  358. req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
  359. if err := req.Error(); err != nil {
  360. httperrors.GeneralServerError(ctx, w, err)
  361. return
  362. }
  363. module := req.Mod1()
  364. module2 := req.Mod2()
  365. module3 := req.Mod3()
  366. session := req.Session()
  367. query := req.Query()
  368. obj, e := module3.ListInContexts(session, query, []modulebase.ManagerContext{
  369. {InstanceManager: module, InstanceId: req.ResID()},
  370. {InstanceManager: module2, InstanceId: req.ResID2()},
  371. })
  372. if e != nil {
  373. httperrors.GeneralServerError(ctx, w, e)
  374. } else {
  375. appsrv.SendJSON(w, modulebase.ListResult2JSON(obj))
  376. }
  377. }
  378. // create
  379. // create multi
  380. // /<resname>
  381. func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  382. req := newRequest(ctx, w, r).WithMod1()
  383. if err := req.Error(); err != nil {
  384. httperrors.GeneralServerError(ctx, w, err)
  385. return
  386. }
  387. module := req.Mod1()
  388. session := req.Session()
  389. body := req.Body()
  390. count, e := body.Int("__count__")
  391. if e == nil && count > 1 {
  392. bodyDict, ok := body.(*jsonutils.JSONDict)
  393. if !ok {
  394. httperrors.GeneralServerError(ctx, w, fmt.Errorf("Fail to decode body"))
  395. } else {
  396. nbody := bodyDict.Copy("__count__")
  397. ret := module.BatchCreate(session, nbody, int(count))
  398. w.WriteHeader(207)
  399. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  400. }
  401. } else {
  402. obj, e := module.Create(session, body)
  403. if e != nil {
  404. httperrors.GeneralServerError(ctx, w, e)
  405. } else {
  406. appsrv.SendJSON(w, obj)
  407. }
  408. }
  409. }
  410. // batch performAction
  411. // /<resname>/<action>
  412. func (f *ResourceHandlers) batchPerformActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  413. req := newRequest(ctx, w, r).WithMod1()
  414. if err := req.Error(); err != nil {
  415. httperrors.GeneralServerError(ctx, w, err)
  416. return
  417. }
  418. module := req.Mod1()
  419. session := req.Session()
  420. query := req.Query()
  421. body := req.Body()
  422. if idlist, e := query.GetArray("id"); e != nil || len(idlist) == 0 {
  423. if obj, e := module.PerformClassAction(session, req.Action(), body); e != nil {
  424. httperrors.GeneralServerError(ctx, w, e)
  425. } else {
  426. appsrv.SendJSON(w, obj)
  427. }
  428. } else {
  429. ret := module.BatchPerformAction(session, jsonutils.JSONArray2StringArray(idlist), req.Action(), body)
  430. w.WriteHeader(207)
  431. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  432. }
  433. }
  434. // performAction
  435. // create in context
  436. // batch Attach
  437. // /<resname>/<resid>/<action>
  438. func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  439. req := newRequest(ctx, w, r).WithMod1()
  440. if err := req.Error(); err != nil {
  441. httperrors.GeneralServerError(ctx, w, err)
  442. return
  443. }
  444. module := req.Mod1()
  445. session := req.Session()
  446. query := req.Query()
  447. body := req.Body()
  448. var obj jsonutils.JSONObject
  449. var idlist []string
  450. if module2, e := modulebase.GetModule(session, req.Action()); e == nil {
  451. if jmod, e := modulebase.GetJointModule2(session, module, module2); e == nil {
  452. if idlist = fetchIdList(ctx, query, w); idlist == nil {
  453. return
  454. }
  455. ret := jmod.BatchAttach(session, req.ResID(), idlist, body)
  456. w.WriteHeader(207)
  457. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  458. } else if jmod, e := modulebase.GetJointModule2(session, module2, module); e == nil {
  459. if idlist = fetchIdList(ctx, query, w); idlist == nil {
  460. return
  461. }
  462. ret := jmod.BatchAttach2(session, req.ResID(), idlist, body)
  463. w.WriteHeader(207)
  464. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  465. } else {
  466. if obj, e = module2.CreateInContext(session, body, module, req.ResID()); e != nil {
  467. httperrors.GeneralServerError(ctx, w, e)
  468. } else {
  469. appsrv.SendJSON(w, obj)
  470. }
  471. }
  472. } else {
  473. if obj, e = module.PerformAction(session, req.ResID(), req.Action(), body); e != nil {
  474. httperrors.GeneralServerError(ctx, w, e)
  475. } else {
  476. appsrv.SendJSON(w, obj)
  477. }
  478. }
  479. }
  480. // joint attach
  481. // /<resname>/<resid>/<resname2>/<resid2>
  482. func (f *ResourceHandlers) attachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  483. req := newRequest(ctx, w, r).WithMod1().WithMod2()
  484. if err := req.Error(); err != nil {
  485. httperrors.GeneralServerError(ctx, w, err)
  486. return
  487. }
  488. module := req.Mod1()
  489. module2 := req.Mod2()
  490. session := req.Session()
  491. body := req.Body()
  492. jmod, e := modulebase.GetJointModule2(session, module, module2)
  493. if e != nil {
  494. httperrors.NotFoundError(ctx, w, "resource %s-%s not exists", req.ResName(), req.ResName2())
  495. return
  496. }
  497. obj, e := jmod.Attach(session, req.ResID(), req.ResID2(), body)
  498. if e != nil {
  499. httperrors.GeneralServerError(ctx, w, e)
  500. } else {
  501. appsrv.SendJSON(w, obj)
  502. }
  503. }
  504. // batchPut
  505. // PUT /<resname>
  506. func (f *ResourceHandlers) batchUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  507. req := newRequest(ctx, w, r).WithMod1()
  508. if err := req.Error(); err != nil {
  509. httperrors.GeneralServerError(ctx, w, err)
  510. return
  511. }
  512. module := req.Mod1()
  513. query := req.Query()
  514. body := req.Body()
  515. idlist := fetchIdList(ctx, query, w)
  516. if idlist == nil {
  517. return
  518. }
  519. var ret []printutils.SubmitResult
  520. if jsonutils.QueryBoolean(query, "batch_params", false) {
  521. bodys, err := body.GetArray()
  522. if err != nil {
  523. httperrors.GeneralServerError(ctx, w, err)
  524. return
  525. }
  526. ret = module.BatchParamsUpdate(req.Session(), idlist, bodys)
  527. } else {
  528. ret = module.BatchUpdate(req.Session(), idlist, body)
  529. }
  530. w.WriteHeader(207)
  531. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  532. }
  533. // batchPatch
  534. // PATCH /<resname>/<resid>
  535. func (f *ResourceHandlers) batchPatchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  536. req := newRequest(ctx, w, r).WithMod1()
  537. if err := req.Error(); err != nil {
  538. httperrors.GeneralServerError(ctx, w, err)
  539. return
  540. }
  541. module := req.Mod1()
  542. query := req.Query()
  543. body := req.Body()
  544. idlist := fetchIdList(ctx, query, w)
  545. if idlist == nil {
  546. return
  547. }
  548. ret := module.BatchPatch(req.Session(), idlist, body)
  549. w.WriteHeader(207)
  550. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  551. }
  552. // put single
  553. // PUT /<resname>/<resid>
  554. func (f *ResourceHandlers) updateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  555. req := newRequest(ctx, w, r).WithMod1()
  556. if err := req.Error(); err != nil {
  557. httperrors.GeneralServerError(ctx, w, err)
  558. return
  559. }
  560. module := req.Mod1()
  561. body := req.Body()
  562. obj, e := module.Update(req.Session(), req.ResID(), body)
  563. if e != nil {
  564. httperrors.GeneralServerError(ctx, w, e)
  565. } else {
  566. appsrv.SendJSON(w, obj)
  567. }
  568. }
  569. // patch single
  570. // PATCH /<resname>/<resid>
  571. func (f *ResourceHandlers) patchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  572. req := newRequest(ctx, w, r).WithMod1()
  573. if err := req.Error(); err != nil {
  574. httperrors.GeneralServerError(ctx, w, err)
  575. return
  576. }
  577. module := req.Mod1()
  578. body := req.Body()
  579. obj, e := module.Patch(req.Session(), req.ResID(), body)
  580. if e != nil {
  581. httperrors.GeneralServerError(ctx, w, e)
  582. } else {
  583. appsrv.SendJSON(w, obj)
  584. }
  585. }
  586. // update joint
  587. // update in context
  588. // PUT /<resname>/<resid>/<resname2>/<resid2>
  589. func (f *ResourceHandlers) updateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  590. req := newRequest(ctx, w, r).WithMod1().WithMod2()
  591. if err := req.Error(); err != nil {
  592. httperrors.GeneralServerError(ctx, w, err)
  593. return
  594. }
  595. session := req.Session()
  596. module := req.Mod1()
  597. module2 := req.Mod2()
  598. query := req.Query()
  599. body := req.Body()
  600. jmod, e := modulebase.GetJointModule2(session, module, module2)
  601. var obj jsonutils.JSONObject
  602. if e == nil { // update joint
  603. obj, e = jmod.Update(session, req.ResID(), req.ResID2(), query, body)
  604. } else { // update in context
  605. obj, e = module2.PutInContext(session, req.ResID2(), body, module, req.ResID())
  606. }
  607. if e != nil {
  608. httperrors.GeneralServerError(ctx, w, e)
  609. } else {
  610. appsrv.SendJSON(w, obj)
  611. }
  612. }
  613. func (f *ResourceHandlers) patchJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  614. req := newRequest(ctx, w, r).WithMod1().WithMod2()
  615. if err := req.Error(); err != nil {
  616. httperrors.GeneralServerError(ctx, w, err)
  617. return
  618. }
  619. session := req.Session()
  620. module := req.Mod1()
  621. module2 := req.Mod2()
  622. query := req.Query()
  623. body := req.Body()
  624. jmod, e := modulebase.GetJointModule2(session, module, module2)
  625. var obj jsonutils.JSONObject
  626. if e == nil { // update joint
  627. obj, e = jmod.Patch(session, req.ResID(), req.ResID2(), query, body)
  628. } else { // update in context
  629. obj, e = module2.PatchInContext(session, req.ResID2(), body, module, req.ResID())
  630. }
  631. if e != nil {
  632. httperrors.GeneralServerError(ctx, w, e)
  633. } else {
  634. appsrv.SendJSON(w, obj)
  635. }
  636. }
  637. // * batch update Joint
  638. // * put specific
  639. // /<resname>/<resid>/<resname2>
  640. // /<resname>/<resid>/<spec>
  641. func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  642. req := newRequest(ctx, w, r).WithMod1()
  643. if err := req.Error(); err != nil {
  644. httperrors.GeneralServerError(ctx, w, err)
  645. return
  646. }
  647. session := req.Session()
  648. module := req.Mod1()
  649. body := req.Body()
  650. query := req.Query()
  651. if idlist, _ := query.GetArray("id"); len(idlist) == 0 {
  652. // do put specific
  653. spec := req.ResName2()
  654. obj, e := module.PutSpecific(session, req.ResID(), spec, query, body)
  655. if e != nil {
  656. httperrors.GeneralServerError(ctx, w, e)
  657. } else {
  658. appsrv.SendJSON(w, obj)
  659. }
  660. return
  661. }
  662. req = req.WithMod2()
  663. if err := req.Error(); err != nil {
  664. httperrors.GeneralServerError(ctx, w, err)
  665. return
  666. }
  667. module2 := req.Mod2()
  668. jmod, e := modulebase.GetJointModule2(session, module, module2)
  669. if e != nil { // update joint
  670. httperrors.GeneralServerError(ctx, w, e)
  671. return
  672. }
  673. idlist := fetchIdList(ctx, query, w)
  674. ret := jmod.BatchUpdate(session, req.ResID(), idlist, query, body)
  675. w.WriteHeader(207)
  676. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  677. }
  678. // update in contexts
  679. // /<resname>/<resid>/<resname2>/<resid2>/<resname3>/<resid3>
  680. func (f *ResourceHandlers) updateInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  681. req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
  682. if err := req.Error(); err != nil {
  683. httperrors.GeneralServerError(ctx, w, err)
  684. return
  685. }
  686. obj, e := req.Mod3().PutInContexts(req.Session(), req.ResID3(), req.Body(), []modulebase.ManagerContext{
  687. {InstanceManager: req.Mod1(), InstanceId: req.ResID()},
  688. {InstanceManager: req.Mod2(), InstanceId: req.ResID2()},
  689. })
  690. if e != nil {
  691. httperrors.GeneralServerError(ctx, w, e)
  692. } else {
  693. appsrv.SendJSON(w, obj)
  694. }
  695. }
  696. func (f *ResourceHandlers) patchInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  697. req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
  698. if err := req.Error(); err != nil {
  699. httperrors.GeneralServerError(ctx, w, err)
  700. return
  701. }
  702. module := req.Mod1()
  703. module2 := req.Mod2()
  704. module3 := req.Mod3()
  705. session := req.Session()
  706. body := req.Body()
  707. obj, e := module3.PatchInContexts(session, req.ResID3(), body, []modulebase.ManagerContext{
  708. {InstanceManager: module, InstanceId: req.ResID()},
  709. {InstanceManager: module2, InstanceId: req.ResID2()},
  710. })
  711. if e != nil {
  712. httperrors.GeneralServerError(ctx, w, e)
  713. } else {
  714. appsrv.SendJSON(w, obj)
  715. }
  716. }
  717. // batchDelete
  718. // DELETE /<resname>
  719. func (f *ResourceHandlers) batchDeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  720. req := newRequest(ctx, w, r).WithMod1()
  721. if err := req.Error(); err != nil {
  722. httperrors.GeneralServerError(ctx, w, err)
  723. return
  724. }
  725. idlist := fetchIdList(ctx, req.Query(), w)
  726. if idlist == nil {
  727. return
  728. }
  729. ret := req.Mod1().BatchDeleteWithParam(req.Session(), idlist, req.Query(), req.Body())
  730. w.WriteHeader(207)
  731. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  732. }
  733. // delete single
  734. // DELETE /<resname>/<resid>
  735. func (f *ResourceHandlers) deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  736. req := newRequest(ctx, w, r).WithMod1()
  737. if err := req.Error(); err != nil {
  738. httperrors.GeneralServerError(ctx, w, err)
  739. return
  740. }
  741. obj, e := req.Mod1().DeleteWithParam(req.Session(), req.ResID(), req.Query(), req.Body())
  742. if e != nil {
  743. httperrors.GeneralServerError(ctx, w, e)
  744. } else {
  745. appsrv.SendJSON(w, obj)
  746. }
  747. }
  748. // batch detach
  749. // /<resname>/<resid>/<resname2>
  750. func (f *ResourceHandlers) batchDetachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  751. req := newRequest(ctx, w, r).WithMod1().WithMod2()
  752. if err := req.Error(); err != nil {
  753. httperrors.GeneralServerError(ctx, w, err)
  754. return
  755. }
  756. idlist := fetchIdList(ctx, req.Query(), w)
  757. if idlist == nil {
  758. return
  759. }
  760. session := req.Session()
  761. module := req.Mod1()
  762. module2 := req.Mod2()
  763. jmod, e := modulebase.GetJointModule2(session, module, module2)
  764. var ret []printutils.SubmitResult
  765. if e == nil {
  766. ret = jmod.BatchDetach(session, req.ResID(), idlist)
  767. } else {
  768. jmod, e := modulebase.GetJointModule2(session, module2, module)
  769. if e == nil {
  770. ret = jmod.BatchDetach2(session, req.ResID(), idlist)
  771. } else {
  772. ret = module2.BatchDeleteInContextWithParam(session, idlist, req.Query(), req.Body(), module, req.ResID())
  773. }
  774. }
  775. w.WriteHeader(207)
  776. appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
  777. }
  778. // detach joint
  779. // delete in context
  780. // DELETE /<resname>/<resid>/<resname2>/<resid2>
  781. func (f *ResourceHandlers) detachHandle(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  782. req := newRequest(ctx, w, r).WithMod1().WithMod2()
  783. if err := req.Error(); err != nil {
  784. httperrors.GeneralServerError(ctx, w, err)
  785. return
  786. }
  787. session := req.Session()
  788. module := req.Mod1()
  789. module2 := req.Mod2()
  790. jmod, e := modulebase.GetJointModule2(session, module, module2)
  791. var obj jsonutils.JSONObject
  792. if e == nil { // joint detach
  793. obj, e = jmod.Detach(session, req.ResID(), req.ResID2(), req.Query())
  794. } else {
  795. obj, e = module2.DeleteInContextWithParam(session, req.ResID2(), req.Query(), req.Body(), module, req.ResID())
  796. }
  797. if e != nil {
  798. httperrors.GeneralServerError(ctx, w, e)
  799. } else {
  800. appsrv.SendJSON(w, obj)
  801. }
  802. }
  803. // delete in contexts
  804. // DELETE /<resname>/<resid>/<resname2>/<resid2>/<resname3>/<resid3>
  805. func (f *ResourceHandlers) deleteInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
  806. req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
  807. if err := req.Error(); err != nil {
  808. httperrors.GeneralServerError(ctx, w, err)
  809. return
  810. }
  811. session := req.Session()
  812. module := req.Mod1()
  813. module2 := req.Mod2()
  814. module3 := req.Mod3()
  815. query := req.Query()
  816. body := req.Body()
  817. obj, e := module3.DeleteInContextsWithParam(session, req.ResID3(), query, body, []modulebase.ManagerContext{
  818. {InstanceManager: module, InstanceId: req.ResID()},
  819. {InstanceManager: module2, InstanceId: req.ResID2()},
  820. })
  821. if e != nil {
  822. httperrors.GeneralServerError(ctx, w, e)
  823. } else {
  824. appsrv.SendJSON(w, obj)
  825. }
  826. }