You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

350 lines
7.8 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package api
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "mime/multipart"
  9. "net/http"
  10. "strconv"
  11. "git.tovijaeschke.xyz/tovi/JumboPetstore/database"
  12. "git.tovijaeschke.xyz/tovi/JumboPetstore/models"
  13. schema "github.com/Kangaroux/go-map-schema"
  14. "github.com/gorilla/mux"
  15. )
  16. func verifyStatus(status string) error {
  17. if status != "available" && status != "pending" && status != "sold" {
  18. return errors.New("Invalid status")
  19. }
  20. return nil
  21. }
  22. func deserialsePetJson(data []byte) (models.Pet, error) {
  23. var (
  24. petData models.Pet = models.Pet{}
  25. jsonStructureTest map[string]interface{} = make(map[string]interface{})
  26. jsonStructureTestResults *schema.CompareResults
  27. err error
  28. )
  29. // Verify the JSON has the correct structure
  30. json.Unmarshal(data, &jsonStructureTest)
  31. jsonStructureTestResults, err = schema.CompareMapToStruct(
  32. &petData,
  33. jsonStructureTest,
  34. &schema.CompareOpts{
  35. ConvertibleFunc: CanConvert,
  36. TypeNameFunc: schema.DetailedTypeName,
  37. })
  38. if err != nil {
  39. return petData, err
  40. }
  41. if len(jsonStructureTestResults.MismatchedFields) > 0 {
  42. return petData, errors.New(fmt.Sprintf(
  43. "MismatchedFields found when deserializing data, %s",
  44. jsonStructureTestResults.Errors().Error(),
  45. ))
  46. }
  47. if len(jsonStructureTestResults.MissingFields) > 0 {
  48. return petData, errors.New(fmt.Sprintf(
  49. "MissingFields found when deserializing data, %s",
  50. jsonStructureTestResults.Errors().Error(),
  51. ))
  52. }
  53. // Deserialize the JSON into the struct
  54. err = json.Unmarshal(data, &petData)
  55. if err != nil {
  56. return petData, err
  57. }
  58. err = verifyStatus(petData.Status)
  59. return petData, err
  60. }
  61. func genericJsonReturn(w http.ResponseWriter, code int, msg, typ string) {
  62. var (
  63. responseJsonMap map[string]interface{}
  64. responseJson []byte
  65. err error
  66. )
  67. responseJsonMap = make(map[string]interface{})
  68. w.WriteHeader(code)
  69. responseJsonMap["code"] = code
  70. responseJsonMap["type"] = typ
  71. responseJsonMap["message"] = msg
  72. responseJson, err = json.MarshalIndent(responseJsonMap, "", " ")
  73. if err != nil {
  74. log.Printf("Error occured creating response: %s\n", err.Error())
  75. }
  76. w.Write(responseJson)
  77. }
  78. func PetHandlerCreateUpdate(w http.ResponseWriter, r *http.Request) {
  79. var (
  80. requestBody []byte
  81. petData models.Pet
  82. returnJson []byte
  83. err error
  84. )
  85. log.Printf("Pet handler recieved %s request", r.Method)
  86. requestBody, err = ioutil.ReadAll(r.Body)
  87. if err != nil {
  88. log.Printf("Error encountered reading POST body: %s\n", err.Error())
  89. genericJsonReturn(w, 500, "An error occured", "unknown")
  90. return
  91. }
  92. petData, err = deserialsePetJson(requestBody)
  93. if err != nil {
  94. log.Printf("Invalid data provided to pet POST API: %s\n", err.Error())
  95. genericJsonReturn(w, 405, "Invalid data", "unknown")
  96. return
  97. }
  98. switch r.Method {
  99. case "POST":
  100. err = database.CreatePet(&petData)
  101. if err != nil {
  102. genericJsonReturn(w, 405, "Invalid data", "unknown")
  103. }
  104. break
  105. case "PUT":
  106. err = database.UpdatePet(&petData)
  107. if err != nil {
  108. genericJsonReturn(w, 405, "Invalid data", "unknown")
  109. }
  110. break
  111. }
  112. returnJson, err = json.MarshalIndent(petData, "", " ")
  113. if err != nil {
  114. genericJsonReturn(w, 500, "An error occured", "unknown")
  115. return
  116. }
  117. // Return updated json
  118. w.WriteHeader(http.StatusOK)
  119. w.Write(returnJson)
  120. }
  121. func getPetDataById(w http.ResponseWriter, r *http.Request) (models.Pet, bool) {
  122. var (
  123. petData models.Pet
  124. urlVars map[string]string
  125. idStr string
  126. id int
  127. ok bool
  128. err error
  129. )
  130. urlVars = mux.Vars(r)
  131. idStr, ok = urlVars["petId"]
  132. if !ok {
  133. log.Printf("Error encountered getting id\n")
  134. genericJsonReturn(w, 500, "An error occured", "unknown")
  135. return petData, false
  136. }
  137. id, err = strconv.Atoi(idStr)
  138. if err != nil {
  139. log.Printf("Error encountered converting id to string: %s\n", err.Error())
  140. genericJsonReturn(w, 500, "An error occured", "unknown")
  141. return petData, false
  142. }
  143. petData = database.GetPetById(id)
  144. if petData.Id == 0 {
  145. log.Printf("Could not find pet with id %d\n", id)
  146. genericJsonReturn(w, 404, "Not found", "unknown")
  147. return petData, false
  148. }
  149. return petData, true
  150. }
  151. func GetPetHandler(w http.ResponseWriter, r *http.Request) {
  152. var (
  153. petData models.Pet
  154. returnJson []byte
  155. ok bool
  156. err error
  157. )
  158. petData, ok = getPetDataById(w, r)
  159. if !ok {
  160. return
  161. }
  162. returnJson, err = json.MarshalIndent(petData, "", " ")
  163. if err != nil {
  164. log.Printf("Error encountered when creating pet record: %s\n", err.Error())
  165. genericJsonReturn(w, 500, "An error occured", "unknown")
  166. return
  167. }
  168. // Return updated json
  169. w.WriteHeader(http.StatusOK)
  170. w.Write(returnJson)
  171. }
  172. func UpdatePetHandler(w http.ResponseWriter, r *http.Request) {
  173. var (
  174. petData models.Pet
  175. ok bool
  176. err error
  177. )
  178. petData, ok = getPetDataById(w, r)
  179. if !ok {
  180. return
  181. }
  182. err = r.ParseForm()
  183. if err != nil {
  184. log.Printf("Error encountered parsing form: %s\n", err.Error())
  185. genericJsonReturn(w, 500, "An error occured", "unknown")
  186. return
  187. }
  188. if r.FormValue("name") != "" {
  189. petData.Name = r.FormValue("name")
  190. }
  191. if r.FormValue("status") != "" {
  192. petData.Status = r.FormValue("status")
  193. }
  194. err = database.UpdatePet(&petData)
  195. if err != nil {
  196. log.Printf("Error updating pet: %s\n", err.Error())
  197. genericJsonReturn(w, 500, "An error occured", "unknown")
  198. return
  199. }
  200. }
  201. func DeletePetHandler(w http.ResponseWriter, r *http.Request) {
  202. var (
  203. petData models.Pet
  204. id_str string
  205. ok bool
  206. )
  207. petData, ok = getPetDataById(w, r)
  208. if !ok {
  209. return
  210. }
  211. log.Printf("Marking pet %d as deleted\n", petData.Id)
  212. database.DeletePet(petData)
  213. id_str = strconv.Itoa(petData.Id)
  214. genericJsonReturn(w, 200, id_str, "unknown")
  215. }
  216. func FindByStatusPetHandler(w http.ResponseWriter, r *http.Request) {
  217. var (
  218. status string
  219. petData []models.Pet
  220. returnJson []byte
  221. err error
  222. )
  223. status = r.URL.Query().Get("status")
  224. err = verifyStatus(status)
  225. if err != nil {
  226. log.Printf("Invalid status provided to /pet/findByStatus")
  227. genericJsonReturn(w, 422, "Invalid status", "unknown")
  228. return
  229. }
  230. petData, err = database.GetPetsByStatus(status)
  231. if err != nil {
  232. log.Printf("An error occured in GetPetsByStatus")
  233. genericJsonReturn(w, 500, "An error occured", "unknown")
  234. return
  235. }
  236. returnJson, err = json.MarshalIndent(petData, "", " ")
  237. if err != nil {
  238. log.Printf("An error occured while serializing pet data to JSON")
  239. genericJsonReturn(w, 500, "An error occured", "unknown")
  240. return
  241. }
  242. w.Write(returnJson)
  243. }
  244. func UploadImagePetHandler(w http.ResponseWriter, r *http.Request) {
  245. var (
  246. petData models.Pet
  247. additionalMetadata string
  248. file multipart.File
  249. handler *multipart.FileHeader
  250. fileBytes []byte
  251. fileName string
  252. ok bool
  253. err error
  254. )
  255. petData, ok = getPetDataById(w, r)
  256. if !ok {
  257. return
  258. }
  259. // Upload 10Mb files
  260. r.ParseMultipartForm(10 << 20)
  261. file, handler, err = r.FormFile("file")
  262. if err != nil {
  263. log.Printf("Error retrieving file: %s\n", err.Error())
  264. genericJsonReturn(w, 500, "An error occured", "unknown")
  265. return
  266. }
  267. defer file.Close()
  268. additionalMetadata = r.FormValue("additionalMetadata")
  269. if additionalMetadata == "" {
  270. additionalMetadata = "null"
  271. }
  272. fileBytes, err = ioutil.ReadAll(file)
  273. if err != nil {
  274. log.Printf("An error occured reading POST file: %s\n", err.Error())
  275. genericJsonReturn(w, 500, "An error occured", "unknown")
  276. return
  277. }
  278. fileName, err = database.AddPhotoToPet(&petData, handler.Filename, additionalMetadata, fileBytes)
  279. if err != nil {
  280. log.Printf("An error occured adding file to database: %s\n", err.Error())
  281. genericJsonReturn(w, 500, "An error occured", "unknown")
  282. return
  283. }
  284. genericJsonReturn(
  285. w,
  286. 200,
  287. fmt.Sprintf(
  288. "additionalMetadata: %s\nFile uploaded to %s, %d bytes",
  289. additionalMetadata,
  290. fileName,
  291. handler.Size,
  292. ),
  293. "unknown",
  294. )
  295. }