ui.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. // Functions to deal with the agGrid (UI).
  2. package main
  3. import (
  4. "database/sql"
  5. "encoding/json"
  6. "fmt"
  7. "gopkg.in/guregu/null.v3/zero"
  8. "io/ioutil"
  9. "net/http"
  10. "path/filepath"
  11. "runtime"
  12. )
  13. // Auxiliary functions for HTTP handling
  14. // checkErrHTTP returns an error via HTTP and also logs the error.
  15. func checkErrHTTP(w http.ResponseWriter, httpStatus int, errorMessage string, err error) {
  16. if err != nil {
  17. http.Error(w, fmt.Sprintf(errorMessage, err), httpStatus)
  18. pc, file, line, ok := runtime.Caller(1)
  19. Log.Error("(", http.StatusText(httpStatus), ") ", filepath.Base(file), ":", line, ":", pc, ok, " - error:", errorMessage, err)
  20. }
  21. }
  22. // checkErrPanicHTTP returns an error via HTTP and logs the error with a panic.
  23. func checkErrPanicHTTP(w http.ResponseWriter, httpStatus int, errorMessage string, err error) {
  24. if err != nil {
  25. http.Error(w, fmt.Sprintf(errorMessage, err), httpStatus)
  26. pc, file, line, ok := runtime.Caller(1)
  27. Log.Panic("(", http.StatusText(httpStatus), ") ", filepath.Base(file), ":", line, ":", pc, ok, " - panic:", errorMessage, err)
  28. }
  29. }
  30. // logErrHTTP assumes that the error message was already composed and writes it to HTTP and logs it.
  31. // this is mostly to avoid code duplication and make sure that all entries are written similarly
  32. func logErrHTTP(w http.ResponseWriter, httpStatus int, errorMessage string) {
  33. http.Error(w, errorMessage, httpStatus)
  34. Log.Error("(" + http.StatusText(httpStatus) + ") " + errorMessage)
  35. }
  36. // funcName is @Sonia's solution to get the name of the function that Go is currently running.
  37. // This will be extensively used to deal with figuring out where in the code the errors are!
  38. // Source: https://stackoverflow.com/a/10743805/1035977 (20170708)
  39. func funcName() string {
  40. pc, _, _, _ := runtime.Caller(1)
  41. return runtime.FuncForPC(pc).Name()
  42. }
  43. // Main functions to respond to agGrid
  44. //
  45. // Each function class has a struct type to deal with database requests
  46. // objectType is a struct to hold data retrieved from the database, used by several functions (including JSON).
  47. type ObjectType struct {
  48. UUID zero.String
  49. Name zero.String
  50. BotKey zero.String
  51. BotName zero.String
  52. Type zero.String // `json:"string"`
  53. Position zero.String
  54. Rotation zero.String
  55. Velocity zero.String
  56. LastUpdate zero.String
  57. Origin zero.String
  58. Phantom zero.String // `json:"string"`
  59. Prims zero.String // `json:"string"`
  60. BBHi zero.String
  61. BBLo zero.String
  62. Coords_region string // These two are not on the database but calculated on demand (20170722)
  63. Coords_xyz []string // can be a string since it will never be deJSONified
  64. }
  65. // uiObjects creates a JSON representation of the Obstacles table and spews it out.
  66. func uiObjects(w http.ResponseWriter, r *http.Request) {
  67. var (
  68. rowArr []interface{}
  69. Object ObjectType
  70. )
  71. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  72. checkErrPanic(err)
  73. defer db.Close()
  74. // query
  75. rows, err := db.Query("SELECT * FROM Obstacles")
  76. checkErr(err)
  77. for rows.Next() {
  78. err = rows.Scan(
  79. &Object.UUID,
  80. &Object.Name,
  81. &Object.BotKey,
  82. &Object.BotName,
  83. &Object.Type,
  84. &Object.Position,
  85. &Object.Rotation,
  86. &Object.Velocity,
  87. &Object.LastUpdate,
  88. &Object.Origin,
  89. &Object.Phantom,
  90. &Object.Prims,
  91. &Object.BBHi,
  92. &Object.BBLo,
  93. )
  94. // Log.Debug("Row extracted:", Object)
  95. rowArr = append(rowArr, Object)
  96. }
  97. checkErr(err)
  98. defer rows.Close()
  99. // produces neatly indented output; see https://blog.golang.org/json-and-go but especially http://stackoverflow.com/a/37084385/1035977
  100. if data, err := json.MarshalIndent(rowArr, "", " "); err != nil {
  101. checkErr(err)
  102. } else {
  103. // Log.Debugf("json.MarshalIndent:\n%s\n\n", data)
  104. _, err := fmt.Fprintf(w, "%s", data)
  105. //if (err == nil) { Log.Debugf("Wrote %d bytes to interface\n", n) } else { checkErr(err) }
  106. checkErr(err)
  107. }
  108. // return
  109. }
  110. // uiObjectsUpdate receives a JSON representation of one row (from the agGrid) in order to update our database.
  111. func uiObjectsUpdate(w http.ResponseWriter, r *http.Request) {
  112. body, err := ioutil.ReadAll(r.Body) // from https://stackoverflow.com/questions/15672556/handling-json-post-request-in-go (20170524)
  113. checkErrPanic(err)
  114. // Log.Debug("\nBody is >>", string(body), "<<")
  115. var obj ObjectType
  116. err = json.Unmarshal(body, &obj)
  117. checkErrPanic(err)
  118. // Log.Debug("\nJSON decoded body is >>", obj, "<<")
  119. // update database
  120. // open database connection and see if we can update the inventory for this object
  121. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  122. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  123. defer db.Close()
  124. stmt, err := db.Prepare("REPLACE INTO Obstacles (`UUID`, `Name`, `BotKey`, `BotName`, `Type`, `Position`, `Rotation`, `Velocity`, `LastUpdate`, `Origin`, `Phantom`, `Prims`, `BBHi`, `BBLo`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)")
  125. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace prepare failed:", err)
  126. defer stmt.Close()
  127. _, err = stmt.Exec(obj.UUID, obj.Name, obj.BotKey, obj.BotName, obj.Type, obj.Position,
  128. obj.Rotation, obj.Velocity, obj.LastUpdate, obj.Origin, obj.Phantom, obj.Prims, obj.BBHi, obj.BBLo)
  129. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace exec failed:", err)
  130. // w.WriteHeader(http.StatusOK)
  131. // w.Header().Set("Content-type", "text/plain; charset=utf-8")
  132. // fmt.Fprintln(w, obj, "successfully updated.")
  133. // Log.Debug(obj, "successfully updated.")
  134. // return
  135. }
  136. // uiObjectsRemove receives a list of UUIDs to remove from the Obstacles table.
  137. func uiObjectsRemove(w http.ResponseWriter, r *http.Request) {
  138. body, err := ioutil.ReadAll(r.Body)
  139. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Cannot read body of HTTP Request:", err)
  140. // Log.Debug("\nObjects body is >>", string(body), "<<")
  141. // open database connection and see if we can remove the object UUIDs we got
  142. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  143. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  144. defer db.Close()
  145. _, err = db.Exec(fmt.Sprintf("DELETE FROM Obstacles WHERE UUID IN (%s)", string(body)))
  146. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Objects remove failed:", err)
  147. Log.Debug("Object UUIDs >>", string(body), "<< successfully removed.")
  148. }
  149. // agentType is a struct to hold data retrieved from the database.
  150. type AgentType struct {
  151. UUID zero.String
  152. Name zero.String
  153. OwnerName zero.String
  154. OwnerKey zero.String
  155. Location zero.String
  156. Position zero.String
  157. Rotation zero.String
  158. Velocity zero.String
  159. Energy zero.String
  160. Money zero.String
  161. Happiness zero.String
  162. Class zero.String
  163. SubType zero.String
  164. PermURL zero.String
  165. LastUpdate zero.String
  166. BestPath zero.String
  167. SecondBestPath zero.String
  168. CurrentTarget zero.String
  169. Coords_region string
  170. Coords_xyz []string
  171. }
  172. // uiAgents creates a JSON representation of the Agents table and spews it out.
  173. func uiAgents(w http.ResponseWriter, r *http.Request) {
  174. var (
  175. rowArr []interface{}
  176. Agent AgentType
  177. )
  178. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  179. checkErrPanic(err)
  180. defer db.Close()
  181. rows, err := db.Query("SELECT * FROM Agents")
  182. checkErr(err)
  183. for rows.Next() {
  184. err = rows.Scan(
  185. &Agent.UUID,
  186. &Agent.Name,
  187. &Agent.OwnerName,
  188. &Agent.OwnerKey,
  189. &Agent.Location,
  190. &Agent.Position,
  191. &Agent.Rotation,
  192. &Agent.Velocity,
  193. &Agent.Energy,
  194. &Agent.Money,
  195. &Agent.Happiness,
  196. &Agent.Class,
  197. &Agent.SubType,
  198. &Agent.PermURL,
  199. &Agent.LastUpdate,
  200. &Agent.BestPath,
  201. &Agent.SecondBestPath,
  202. &Agent.CurrentTarget,
  203. )
  204. rowArr = append(rowArr, Agent)
  205. }
  206. checkErr(err)
  207. defer rows.Close()
  208. if data, err := json.MarshalIndent(rowArr, "", " "); err != nil {
  209. checkErr(err)
  210. } else {
  211. _, err := fmt.Fprintf(w, "%s", data)
  212. checkErr(err)
  213. }
  214. // return
  215. }
  216. // uiAgentsUpdate receives a JSON representation of one row (from the agGrid) in order to update our database.
  217. func uiAgentsUpdate(w http.ResponseWriter, r *http.Request) {
  218. body, err := ioutil.ReadAll(r.Body)
  219. checkErrPanic(err)
  220. var ag AgentType
  221. err = json.Unmarshal(body, &ag)
  222. checkErrPanic(err)
  223. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  224. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  225. defer db.Close()
  226. stmt, err := db.Prepare("REPLACE INTO Agents (`UUID`, `Name`, `OwnerName`, `OwnerKey`, `Location`, `Position`, `Rotation`, `Velocity`, `Energy`, `Money`, `Happiness`, `Class`, `SubType`, `PermURL`, `LastUpdate`, `BestPath`, `SecondBestPath`, `CurrentTarget`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")
  227. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace prepare failed:", err)
  228. defer stmt.Close()
  229. _, err = stmt.Exec(ag.UUID, ag.Name, ag.OwnerName, ag.OwnerKey, ag.Location, ag.Position,
  230. ag.Rotation, ag.Velocity, ag.Energy, ag.Money, ag.Happiness, ag.Class, ag.SubType, ag.PermURL,
  231. ag.LastUpdate, ag.BestPath, ag.SecondBestPath, ag.CurrentTarget)
  232. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace exec failed:", err)
  233. // return
  234. }
  235. // uiAgentsRemove receives a list of UUIDs to remove from the Agents table.
  236. func uiAgentsRemove(w http.ResponseWriter, r *http.Request) {
  237. body, err := ioutil.ReadAll(r.Body)
  238. checkErrPanic(err)
  239. // Log.Debug("\nAgents Body is >>", string(body), "<<")
  240. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  241. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  242. defer db.Close()
  243. _, err = db.Exec(fmt.Sprintf("DELETE FROM Agents WHERE UUID IN (%s)", string(body)))
  244. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Agents remove failed:", err)
  245. Log.Debug("Agents UUIDs >>", string(body), "<< successfully removed.")
  246. }
  247. // PositionType is a struct to hold data retrieved from the database, used by several functions (including JSON).
  248. type PositionType struct {
  249. PermURL zero.String
  250. UUID zero.String
  251. Name zero.String
  252. OwnerName zero.String
  253. Location zero.String
  254. Position zero.String
  255. Rotation zero.String
  256. Velocity zero.String
  257. LastUpdate zero.String
  258. OwnerKey zero.String
  259. ObjectType zero.String
  260. ObjectClass zero.String
  261. RateEnergy zero.String
  262. RateMoney zero.String
  263. RateHappiness zero.String
  264. Coords_region string
  265. Coords_xyz []string
  266. DistanceToAgent float64 // This does not get saved to the database, since it's different for every agent (20170811).
  267. }
  268. // uiPositions creates a JSON representation of the Positions table and spews it out.
  269. func uiPositions(w http.ResponseWriter, r *http.Request) {
  270. var (
  271. rowArr []interface{}
  272. Position PositionType
  273. )
  274. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  275. checkErrPanic(err)
  276. defer db.Close()
  277. // query
  278. rows, err := db.Query("SELECT * FROM Positions")
  279. checkErr(err)
  280. for rows.Next() {
  281. err = rows.Scan(
  282. &Position.PermURL,
  283. &Position.UUID,
  284. &Position.Name,
  285. &Position.OwnerName,
  286. &Position.Location,
  287. &Position.Position,
  288. &Position.Rotation,
  289. &Position.Velocity,
  290. &Position.LastUpdate,
  291. &Position.OwnerKey,
  292. &Position.ObjectType,
  293. &Position.ObjectClass,
  294. &Position.RateEnergy,
  295. &Position.RateMoney,
  296. &Position.RateHappiness,
  297. )
  298. rowArr = append(rowArr, Position)
  299. }
  300. checkErr(err)
  301. defer rows.Close()
  302. if data, err := json.MarshalIndent(rowArr, "", " "); err != nil {
  303. checkErr(err)
  304. } else {
  305. _, err := fmt.Fprintf(w, "%s", data)
  306. checkErr(err)
  307. }
  308. // return
  309. }
  310. // uiPositionsUpdate receives a JSON representation of one row (from the agGrid) in order to update our database.
  311. func uiPositionsUpdate(w http.ResponseWriter, r *http.Request) {
  312. body, err := ioutil.ReadAll(r.Body)
  313. checkErrPanic(err)
  314. var pos PositionType
  315. err = json.Unmarshal(body, &pos)
  316. checkErrPanic(err)
  317. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  318. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  319. defer db.Close()
  320. stmt, err := db.Prepare("REPLACE INTO Positions (`PermURL`, `UUID`, `Name`, `OwnerName`, `Location`, `Position`, `Rotation`, `Velocity`, `LastUpdate`, `OwnerKey`, `ObjectType`, `ObjectClass`, `RateEnergy`, `RateMoney`, `RateHappiness`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")
  321. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace prepare failed:", err)
  322. defer stmt.Close()
  323. _, err = stmt.Exec(pos.PermURL, pos.UUID, pos.Name, pos.OwnerName, pos.Location, pos.Position,
  324. pos.Rotation, pos.Velocity, pos.LastUpdate, pos.OwnerKey, pos.ObjectType, pos.ObjectClass,
  325. pos.RateEnergy, pos.RateMoney, pos.RateHappiness)
  326. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace exec failed:", err)
  327. // return
  328. }
  329. // uiPositionsRemove receives a list of UUIDs to remove from the Positions table.
  330. func uiPositionsRemove(w http.ResponseWriter, r *http.Request) {
  331. body, err := ioutil.ReadAll(r.Body)
  332. checkErrPanic(err)
  333. // Log.Debug("\nPositions Body is >>", string(body), "<<")
  334. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  335. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  336. defer db.Close()
  337. _, err = db.Exec(fmt.Sprintf("DELETE FROM Positions WHERE UUID IN (%s)", string(body)))
  338. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Positions remove failed:", err)
  339. Log.Debug("Positions UUIDs >>", string(body), "<< successfully removed.")
  340. }
  341. // inventoryType is a struct to hold data retrieved from the database, used by several functions (including JSON).
  342. type inventoryType struct {
  343. UUID zero.String
  344. Name zero.String
  345. Type zero.String
  346. LastUpdate zero.String
  347. Permissions zero.String
  348. }
  349. // uiInventory creates a JSON representation of the Inventory table and spews it out.
  350. func uiInventory(w http.ResponseWriter, r *http.Request) {
  351. var (
  352. rowArr []interface{}
  353. Inventory inventoryType
  354. )
  355. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  356. checkErrPanic(err)
  357. defer db.Close()
  358. // query
  359. rows, err := db.Query("SELECT * FROM Inventory")
  360. checkErr(err)
  361. for rows.Next() {
  362. err = rows.Scan(
  363. &Inventory.UUID,
  364. &Inventory.Name,
  365. &Inventory.Type,
  366. &Inventory.LastUpdate,
  367. &Inventory.Permissions,
  368. )
  369. rowArr = append(rowArr, Inventory)
  370. }
  371. checkErr(err)
  372. defer rows.Close()
  373. if data, err := json.MarshalIndent(rowArr, "", " "); err != nil {
  374. checkErr(err)
  375. } else {
  376. _, err := fmt.Fprintf(w, "%s", data)
  377. checkErr(err)
  378. }
  379. // return
  380. }
  381. // uiInventoryUpdate receives a JSON representation of one row (from the agGrid) in order to update our database.
  382. func uiInventoryUpdate(w http.ResponseWriter, r *http.Request) {
  383. body, err := ioutil.ReadAll(r.Body)
  384. checkErrPanic(err)
  385. var inv inventoryType
  386. err = json.Unmarshal(body, &inv)
  387. checkErrPanic(err)
  388. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  389. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  390. defer db.Close()
  391. stmt, err := db.Prepare("REPLACE INTO Inventory (`UUID`, `Name`, `Type`, `LastUpdate`, `Permissions`) VALUES (?,?,?,?,?)")
  392. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace prepare failed:", err)
  393. defer stmt.Close()
  394. _, err = stmt.Exec(inv.UUID, inv.Name, inv.Type, inv.LastUpdate, inv.Permissions)
  395. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace exec failed:", err)
  396. // return
  397. }
  398. // uiInventoryRemove receives a list of UUIDs to remove from the Inventory table.
  399. func uiInventoryRemove(w http.ResponseWriter, r *http.Request) {
  400. body, err := ioutil.ReadAll(r.Body)
  401. checkErrPanic(err)
  402. // Log.Debug("\nInventory Body is >>", string(body), "<<")
  403. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  404. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  405. defer db.Close()
  406. _, err = db.Exec(fmt.Sprintf("DELETE FROM Inventory WHERE UUID IN (%s)", string(body)))
  407. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Inventory remove failed:", err)
  408. Log.Debug("Inventory UUIDs >>", string(body), "<< successfully removed.")
  409. }
  410. // userManagementType is a struct to hold data retrieved from the database, used by several functions (including JSON).
  411. type userManagementType struct {
  412. Email zero.String
  413. Password zero.String
  414. }
  415. // uiUserManagement creates a JSON representation of the Users table and spews it out.
  416. func uiUserManagement(w http.ResponseWriter, r *http.Request) {
  417. var (
  418. rowArr []interface{}
  419. UserManagement userManagementType
  420. )
  421. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  422. checkErrPanic(err)
  423. defer db.Close()
  424. // query
  425. rows, err := db.Query("SELECT * FROM Users")
  426. checkErrPanic(err)
  427. for rows.Next() {
  428. err = rows.Scan(
  429. &UserManagement.Email,
  430. &UserManagement.Password,
  431. )
  432. rowArr = append(rowArr, UserManagement)
  433. }
  434. checkErr(err)
  435. defer rows.Close()
  436. if data, err := json.MarshalIndent(rowArr, "", " "); err != nil {
  437. checkErr(err)
  438. } else {
  439. _, err := fmt.Fprintf(w, "%s", data)
  440. checkErr(err)
  441. }
  442. // return
  443. }
  444. // uiUserManagementUpdate receives a JSON representation of one row (from the agGrid) in order to update our database.
  445. func uiUserManagementUpdate(w http.ResponseWriter, r *http.Request) {
  446. body, err := ioutil.ReadAll(r.Body)
  447. checkErrPanic(err)
  448. var user userManagementType
  449. err = json.Unmarshal(body, &user)
  450. checkErrPanic(err)
  451. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  452. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  453. defer db.Close()
  454. stmt, err := db.Prepare("REPLACE INTO Users (`Email`, `Password`) VALUES (?,?)")
  455. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace prepare failed:", err)
  456. defer stmt.Close()
  457. _, err = stmt.Exec(user.Email, user.Password)
  458. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Replace exec failed:", err)
  459. // return
  460. }
  461. // uiUserManagementRemove receives a list of UUIDs to remove from the UserManagement table.
  462. func uiUserManagementRemove(w http.ResponseWriter, r *http.Request) {
  463. body, err := ioutil.ReadAll(r.Body)
  464. checkErrPanic(err)
  465. // Log.Debug("\nInventory Body is >>", string(body), "<<")
  466. db, err := sql.Open(PDO_Prefix, GoBotDSN)
  467. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Connect failed:", err)
  468. defer db.Close()
  469. _, err = db.Exec(fmt.Sprintf("DELETE FROM Users WHERE Email IN (%s)", string(body)))
  470. checkErrPanicHTTP(w, http.StatusServiceUnavailable, funcName() + ": Users remove failed:", err)
  471. Log.Debug("User(s) Email(s) >>", string(body), "<< successfully removed.")
  472. }