modelapi.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. package api
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "strconv"
  7. "github.com/go-chi/chi"
  8. "github.com/go-chi/render"
  9. "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/dao"
  10. "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/internal"
  11. "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/model"
  12. "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/worker"
  13. )
  14. //DeleteRefHeader header key for the delete reference options
  15. const DeleteRefHeader = "X-mcs-deleteref"
  16. /*
  17. ModelRoutes getting all routes for the config endpoint
  18. */
  19. func ModelRoutes() *chi.Mux {
  20. router := chi.NewRouter()
  21. router.With(RoleCheck([]string{"edit"})).Post("/{bename}/{model}/", PostModelEndpoint)
  22. //TODO insert bulk import api
  23. router.With(RoleCheck([]string{"edit", "read"})).Get("/{bename}/{model}/count", GetModelCountEndpoint)
  24. router.With(RoleCheck([]string{"edit", "read"})).With(Paginate).Get("/{bename}/{model}/", GetManyModelsEndpoint)
  25. router.With(RoleCheck([]string{"edit", "read"})).Get("/{bename}/{model}/{modelid}", GetModelEndpoint)
  26. router.With(RoleCheck([]string{"edit"})).Put("/{bename}/{model}/{modelid}", PutModelEndpoint)
  27. router.With(RoleCheck([]string{"edit"})).Delete("/{bename}/{model}/{modelid}", DeleteModelEndpoint)
  28. return router
  29. }
  30. //PostModelEndpoint , this method will always return 201
  31. func PostModelEndpoint(response http.ResponseWriter, request *http.Request) {
  32. backend := chi.URLParam(request, "bename")
  33. mymodel := chi.URLParam(request, "model")
  34. route := model.Route{
  35. Backend: backend,
  36. Model: mymodel,
  37. }
  38. route = enrichRouteInformation(request, route)
  39. data := &model.JSONMap{}
  40. if err := render.Decode(request, data); err != nil {
  41. render.Render(response, request, ErrInvalidRequest(err))
  42. return
  43. }
  44. bemodel := *data
  45. log.Infof("POST: path: %s, route: %s \n", request.URL.Path, route.String())
  46. validModel, err := worker.Validate(route, bemodel)
  47. if err != nil {
  48. if pe, ok := err.(worker.ErrValidationError); ok {
  49. render.Render(response, request, ErrInvalidRequest(pe))
  50. return
  51. }
  52. if err == dao.ErrNotImplemented {
  53. render.Render(response, request, ErrNotImplemted)
  54. return
  55. }
  56. if err == worker.ErrBackendNotFound || err == worker.ErrBackendModelNotFound {
  57. render.Render(response, request, ErrNotFound)
  58. return
  59. }
  60. render.Render(response, request, ErrInternalServer(err))
  61. return
  62. }
  63. if validModel == nil {
  64. render.Render(response, request, ErrInvalidRequest(errors.New("data model not valid")))
  65. return
  66. }
  67. validModel, err = worker.Store(route, validModel)
  68. if err != nil {
  69. if err == dao.ErrNotImplemented {
  70. render.Render(response, request, ErrNotImplemted)
  71. return
  72. }
  73. if err == dao.ErrUniqueIndexError {
  74. render.Render(response, request, ErrUniqueIndexError)
  75. return
  76. }
  77. render.Render(response, request, ErrInternalServer(err))
  78. return
  79. }
  80. route.Identity = validModel[internal.AttributeID].(string)
  81. buildLocationHeader(response, request, route)
  82. render.Status(request, http.StatusCreated)
  83. render.JSON(response, request, validModel)
  84. }
  85. //GetManyModelsEndpoint searching for a list of model instances
  86. func GetManyModelsEndpoint(response http.ResponseWriter, request *http.Request) {
  87. offset := request.Context().Value(contextKeyOffset)
  88. limit := request.Context().Value(contextKeyLimit)
  89. log.Infof("GET many: offset: %d, limit: %d", offset, limit)
  90. backend := chi.URLParam(request, "bename")
  91. mymodel := chi.URLParam(request, "model")
  92. route := model.Route{
  93. Backend: backend,
  94. Model: mymodel,
  95. }
  96. route = enrichRouteInformation(request, route)
  97. log.Infof("GET many: path: %s, route: %s", request.URL.Path, route.String())
  98. query := request.URL.Query().Get("query")
  99. log.Infof("query: %s, offset: %d, limit: %d", query, offset, limit)
  100. //owner, _, _ := request.BasicAuth()
  101. n, models, err := worker.Query(route, query, offset.(int), limit.(int))
  102. if err != nil {
  103. if err == dao.ErrNotImplemented {
  104. render.Render(response, request, ErrNotImplemted)
  105. return
  106. }
  107. render.Render(response, request, ErrInternalServer(err))
  108. return
  109. }
  110. m := make(map[string]interface{})
  111. m["data"] = models
  112. m["found"] = n
  113. m["count"] = len(models)
  114. m["query"] = query
  115. m["offset"] = offset
  116. m["limit"] = limit
  117. render.JSON(response, request, m)
  118. }
  119. //GetModelCountEndpoint getting a model with an identifier
  120. func GetModelCountEndpoint(response http.ResponseWriter, request *http.Request) {
  121. backend := chi.URLParam(request, "bename")
  122. mymodel := chi.URLParam(request, "model")
  123. route := model.Route{
  124. Backend: backend,
  125. Model: mymodel,
  126. }
  127. route = enrichRouteInformation(request, route)
  128. log.Infof("GET count: path: %s, route: %s", request.URL.Path, route.String())
  129. modelCount, err := worker.GetCount(route)
  130. if err != nil {
  131. if err == dao.ErrNotImplemented {
  132. render.Render(response, request, ErrNotImplemted)
  133. return
  134. }
  135. if err == dao.ErrNoDocument {
  136. render.Render(response, request, ErrNotFound)
  137. return
  138. }
  139. render.Render(response, request, ErrInternalServer(err))
  140. return
  141. }
  142. m := make(map[string]interface{})
  143. m["found"] = modelCount
  144. render.JSON(response, request, m)
  145. }
  146. //GetModelEndpoint getting a model with an identifier
  147. func GetModelEndpoint(response http.ResponseWriter, request *http.Request) {
  148. backend := chi.URLParam(request, "bename")
  149. mymodel := chi.URLParam(request, "model")
  150. modelid := chi.URLParam(request, "modelid")
  151. route := model.Route{
  152. Backend: backend,
  153. Model: mymodel,
  154. Identity: modelid,
  155. }
  156. route = enrichRouteInformation(request, route)
  157. log.Infof("GET: path: %s, route: %s", request.URL.Path, route.String())
  158. model, err := worker.Get(route)
  159. if err != nil {
  160. if err == dao.ErrNotImplemented {
  161. render.Render(response, request, ErrNotImplemted)
  162. return
  163. }
  164. if err == dao.ErrNoDocument {
  165. render.Render(response, request, ErrNotFound)
  166. return
  167. }
  168. render.Render(response, request, ErrInternalServer(err))
  169. return
  170. }
  171. render.JSON(response, request, model)
  172. }
  173. //PutModelEndpoint change a model
  174. func PutModelEndpoint(response http.ResponseWriter, request *http.Request) {
  175. backend := chi.URLParam(request, "bename")
  176. mymodel := chi.URLParam(request, "model")
  177. modelid := chi.URLParam(request, "modelid")
  178. route := model.Route{
  179. Backend: backend,
  180. Model: mymodel,
  181. Identity: modelid,
  182. }
  183. route = enrichRouteInformation(request, route)
  184. log.Infof("PUT: path: %s, route: %s", request.URL.Path, route.String())
  185. data := &model.JSONMap{}
  186. if err := render.Decode(request, data); err != nil {
  187. render.Render(response, request, ErrInvalidRequest(err))
  188. return
  189. }
  190. bemodel := *data
  191. validModel, err := worker.Validate(route, bemodel)
  192. if err != nil {
  193. if err == dao.ErrNotImplemented {
  194. render.Render(response, request, ErrNotImplemted)
  195. return
  196. }
  197. render.Render(response, request, ErrInternalServer(err))
  198. return
  199. }
  200. if validModel == nil {
  201. render.Render(response, request, ErrInvalidRequest(errors.New("data model not valid")))
  202. return
  203. }
  204. validModel, err = worker.Update(route, validModel)
  205. if err != nil {
  206. if err == dao.ErrNoDocument {
  207. render.Render(response, request, ErrNotFound)
  208. return
  209. }
  210. if err == dao.ErrNotImplemented {
  211. render.Render(response, request, ErrNotImplemted)
  212. return
  213. }
  214. render.Render(response, request, ErrInternalServer(err))
  215. return
  216. }
  217. route.Identity = validModel[internal.AttributeID].(string)
  218. buildLocationHeader(response, request, route)
  219. render.Status(request, http.StatusCreated)
  220. render.JSON(response, request, validModel)
  221. }
  222. //DeleteModelEndpoint deleting a model
  223. func DeleteModelEndpoint(response http.ResponseWriter, request *http.Request) {
  224. backend := chi.URLParam(request, "bename")
  225. mymodel := chi.URLParam(request, "model")
  226. modelid := chi.URLParam(request, "modelid")
  227. route := model.Route{
  228. Backend: backend,
  229. Model: mymodel,
  230. Identity: modelid,
  231. }
  232. route = enrichRouteInformation(request, route)
  233. deleteRef := isDeleteRef(request)
  234. log.Infof("DELETE: path: %s, route: %s, delRef: %t", request.URL.Path, route.String(), deleteRef)
  235. err := worker.Delete(route, deleteRef)
  236. if err != nil {
  237. if err == dao.ErrNoDocument {
  238. render.Render(response, request, ErrNotFound)
  239. return
  240. }
  241. if err == dao.ErrNotImplemented {
  242. render.Render(response, request, ErrNotImplemted)
  243. return
  244. }
  245. render.Render(response, request, ErrInternalServer(err))
  246. return
  247. }
  248. MsgResponse(response, http.StatusOK, "model deleted.")
  249. }
  250. func isDeleteRef(request *http.Request) bool {
  251. deleteRef := true
  252. if request.Header.Get(DeleteRefHeader) != "" {
  253. b, err := strconv.ParseBool(request.Header.Get(DeleteRefHeader))
  254. if err == nil {
  255. deleteRef = b
  256. }
  257. }
  258. return deleteRef
  259. }
  260. func enrichRouteInformation(request *http.Request, route model.Route) model.Route {
  261. if request.Header.Get(APIKeyHeader) != "" {
  262. route.Apikey = request.Header.Get(APIKeyHeader)
  263. }
  264. if request.Header.Get(SystemHeader) != "" {
  265. route.SystemID = request.Header.Get(SystemHeader)
  266. }
  267. username, _, _ := request.BasicAuth()
  268. if username != "" {
  269. route.Username = username
  270. }
  271. return route
  272. }
  273. func buildLocationHeader(response http.ResponseWriter, request *http.Request, route model.Route) {
  274. loc := fmt.Sprintf("%s/%s", request.URL.Path, route.Identity)
  275. response.Header().Add("Location", loc)
  276. }