PopufareAPI.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. #!/usr/bin/python3
  2. #
  3. # Copyright (c) 2019 Clementine Computing LLC.
  4. #
  5. # This file is part of PopuFare.
  6. #
  7. # PopuFare is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # PopuFare is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. ## WORK IN PROGRESS
  21. import json
  22. import mysql.connector
  23. import time
  24. import datetime
  25. import copy
  26. #conn = mysql.connector.connect(user='bus', password='bus', host='localhost', database='busdb', port=3306)
  27. _USER = 'busapi'
  28. _PASSWORD = 'bus'
  29. _HOST = 'localhost'
  30. _DATABASE = 'busdb'
  31. _PORT = 5506
  32. Function = [
  33. "User",
  34. "Card",
  35. "Pass",
  36. "Log",
  37. "PricePoints",
  38. "AdminGetCard", "AdminGetCards", "AdminGetPass", "AdminGetUser",
  39. "AdminGetAdmin", "AdminGetPassesOnCard", "AdminGetPendingQueue", "AdminProcessPendingQueue",
  40. "AdminRemovePendingQueue", "AdminCreateCardBlock", "AdminCreateCard", "AdminSetUser",
  41. "AdminSetAdmin", "AdminAddPass", "AdminAddCard", "AdminAddUser",
  42. "AdminAddAdmin", "AdminRemovePass", "AdminRemovePasses", "AdminRemoveCard",
  43. "AdminRemoveUser", "AdminRemoveAdmin", "AdminTransferCard", "AdminTransferPass",
  44. "AdminGetPassOptions", "AdminAddCardToUser", "AdminRemoveCardFromUser", "AdminGetAdminPermissions",
  45. "AdminAddAdminPermissions", "AdminRemoveAdminPermissions", "AdminAddAdminApiPermissions", "AdminRemoveAdminApiPermissions",
  46. "AdminSetAdminApiPermissions", "AdminGetCustomCard", "AdminGetAdmins", "AdminSearchCards",
  47. "AdminSearchUsers", "AdminSearchAdmins"]
  48. PASS_FIELDS = ["logical_card_id", "issued", "activated", "deactivated", "firstused", "lastused",
  49. "nrides_orig", "nrides_remain", "nday_orig", "nday_expiration",
  50. "expired", "rule", "queue_order", "comment", "paytype" ]
  51. CARD_FIELDS = ["mag_token", "rfid_token", "comment", "userid", "issued", "deactivated", "lastused",
  52. "firstused", "group_id", "issuetype"]
  53. USER_FIELDS = ["username", "comment", "first_name", "last_name", "phone",
  54. "email", "address", "city", "state", "zip", "passwordhash",
  55. "shipping_address", "shipping_city", "shipping_state", "shipping_zip",
  56. "shipping_name", "shipping_country_code", "shipping_country_name"]
  57. def Request(ctx):
  58. _conn = mysql.connector.connect(user=_USER, password=_PASSWORD, host=_HOST, database=_DATABASE, port=_PORT)
  59. res = {}
  60. if "function" in ctx:
  61. if ctx["function"] == "CardInfo":
  62. res = CardInfo(_conn, ctx)
  63. elif ctx["function"] == "UserInfo":
  64. res = UserInfo(_conn, ctx)
  65. elif ctx["function"] == "User":
  66. res = User(_conn, ctx)
  67. elif ctx["function"] == "Card":
  68. res = Card(_conn, ctx)
  69. elif ctx["function"] == "Pass":
  70. res = Pass(_conn, ctx)
  71. _conn.close()
  72. return res
  73. def CardInfo(db, ctx):
  74. card_res = {}
  75. action = "get"
  76. if "action" in ctx:
  77. action = ctx["action"]
  78. if action == "get":
  79. cardid = -1
  80. if "logical_card_id" in ctx:
  81. cardid = ctx["logical_card_id"]
  82. card_res["logical_card_id"] = cardid
  83. card_res = Card(db, {"action":"get", "logical_card_id": cardid})
  84. card_res["pass"] = []
  85. ## through each of the passes on the card
  86. ##
  87. pass_query = "select user_pass_id from user_pass where logical_card_id = %s and active = 1 and expired = 0 order by queue_order asc"
  88. pass_cursor = db.cursor()
  89. pass_cursor.execute(pass_query, [card_res["logical_card_id"]])
  90. pass_rows = pass_cursor.fetchall()
  91. for pass_row in pass_rows:
  92. pass_res = Pass(db, {"action":"get", "user_pass_id":pass_row[0]})
  93. card_res["pass"].append(pass_res)
  94. elif action == "search":
  95. card_res["cards"] = []
  96. res_cardid = Card(db, ctx)
  97. for cid in res_cardid["logical_card_ids"]:
  98. _c = CardInfo(db, {"action":"get", "logical_card_id":cid})
  99. card_res["cards"].append(_c)
  100. return card_res
  101. def UserInfo(db, ctx):
  102. res = {}
  103. userid = -1
  104. if ("userid" in ctx):
  105. userid = ctx["userid"]
  106. pass_fields = PASS_FIELDS.copy()
  107. card_fields = CARD_FIELDS.copy()
  108. user_fields = USER_FIELDS.copy()
  109. res["userid"] = userid
  110. cursor = db.cursor()
  111. ## fill in user data
  112. ##
  113. res["user"] = {}
  114. fields = USER_FIELDS.copy()
  115. query = "select " + ",".join(fields) + " from users where userid = %s"
  116. cursor.execute(query, [userid])
  117. row = cursor.fetchone()
  118. if row is None:
  119. res["api_comment"] = "user not found"
  120. return res
  121. for idx,f in enumerate(user_fields):
  122. res["user"][f] = row[idx]
  123. ## go through each card and fill in card data and pass data
  124. ##
  125. res["card"] = []
  126. query = "select logical_card_id from user_card where userid = %s and active = 1 order by logical_card_id asc"
  127. card_cursor = db.cursor()
  128. card_cursor.execute(query, [userid])
  129. rows = card_cursor.fetchall()
  130. for row in rows:
  131. card_res = CardInfo(db, {"logical_card_id":row[0]})
  132. res["card"].append(card_res)
  133. return res
  134. def Pass(db, ctx):
  135. res = {}
  136. passid = -1
  137. if ("user_pass_id" in ctx):
  138. passid = ctx["user_pass_id"]
  139. pass_fields = PASS_FIELDS.copy()
  140. cursor = db.cursor()
  141. fields = pass_fields.copy()
  142. field_vals = []
  143. if (ctx["action"] == "get"):
  144. query = "select " + ",".join(pass_fields) + " from user_pass where user_pass_id = %s"
  145. cursor.execute(query, [passid])
  146. row = cursor.fetchone()
  147. if row is not None:
  148. res["user_pass_id"] = passid
  149. for idx,f in enumerate(pass_fields):
  150. if isinstance(row[idx], datetime.datetime):
  151. res[f] = row[idx].strftime("%Y-%M-%d %H:%m:%S")
  152. else:
  153. res[f] = row[idx]
  154. else:
  155. res["api_comment"] = "pass not found"
  156. elif (ctx["action"] == "add"):
  157. fields.append("active")
  158. for f in pass_fields:
  159. if f in ctx: field_vals.append(ctx[f])
  160. else: field_vals.append(None)
  161. field_vals.append(1)
  162. query = "insert into user_pass (" + ",".join(fields) + ") values (" + ",".join(["%s"]*len(fields)) + ")"
  163. cursor.execute(query, field_vals)
  164. res["user_pass_id"] = cursor.lastrowid
  165. elif (ctx["action"] == "update"):
  166. update_field = []
  167. update_val = []
  168. for f in pass_fields:
  169. if f in ctx:
  170. update_field.append(f + "= %s")
  171. update_val.append(ctx[f])
  172. update_val.append(passid)
  173. query = "update user_pass set " + ",".join(update_field) + " where user_pass_id = %s"
  174. cursor.execute(query, update_val)
  175. res["user_pass_id"] = passid
  176. elif (ctx["action"] == "delete"):
  177. query = "delete from user_pass where user_pass_id = %s"
  178. cursor.execute(query, [passid])
  179. db.commit()
  180. return res
  181. def Card(db, ctx):
  182. card_fields = CARD_FIELDS.copy()
  183. res = {}
  184. cardid = -1
  185. if ("logical_card_id" in ctx):
  186. cardid = ctx["logical_card_id"]
  187. cursor = db.cursor()
  188. fields = card_fields.copy()
  189. field_vals = []
  190. if (ctx["action"] == "get"):
  191. query = "select " + ",".join(card_fields) + " from user_card where logical_card_id = %s"
  192. cursor.execute(query, [cardid])
  193. row = cursor.fetchone()
  194. if row is not None:
  195. res["logical_card_id"] = cardid
  196. for idx,f in enumerate(card_fields):
  197. if isinstance(row[idx], datetime.datetime):
  198. res[f] = row[idx].strftime("%Y-%M-%d %H:%m:%S")
  199. else:
  200. res[f] = row[idx]
  201. else:
  202. res["api_comment"] = "card not found"
  203. elif (ctx["action"] == "add"):
  204. fields.append("active")
  205. for f in card_fields:
  206. if f in ctx: field_vals.append(ctx[f])
  207. else: field_vals.append(None)
  208. field_vals.append(1)
  209. query = "insert into user_card (" + ",".join(fields) + ") values (" + ",".join(["%s"]*len(fields)) + ")"
  210. cursor.execute(query, field_vals)
  211. res["logical_card_id"] = cursor.lastrowid
  212. elif (ctx["action"] == "update"):
  213. update_field = []
  214. update_val = []
  215. for f in card_fields:
  216. if f in ctx:
  217. update_field.append(f + "= %s")
  218. update_val.append(ctx[f])
  219. update_val.append(cardid)
  220. query = "update user_card set " + ",".join(update_field) + " where logical_card_id = %s"
  221. print(">>>", query, update_val)
  222. cursor.execute(query, update_val)
  223. res["logical_card_id"] = cardid
  224. elif (ctx["action"] == "delete"):
  225. query = "delete from user_card where logical_card_id = %s"
  226. cursor.execute(query, [cardid])
  227. elif (ctx["action"] == "search"):
  228. query = "select logical_card_id from user_card where "
  229. n_search = 0
  230. if "logical_card_id" in ctx:
  231. query += " logical_card_id = %s"
  232. field_vals.append( ctx["logical_card_id"])
  233. n_search += 1
  234. if "mag_token" in ctx:
  235. query += " mag_token like %s "
  236. field_vals.append( '%' + ctx["mag_token"] + '%')
  237. n_search += 1
  238. if "rfid_token" in ctx:
  239. if len(field_vals)>0: query += " and "
  240. query += " rfid_token like %s "
  241. field_vals.append( '%' + ctx["rfid_token"] + '%')
  242. n_search += 1
  243. query_limit = " "
  244. if "limit" in ctx:
  245. query_limit = " limit %s "
  246. search_vals.append(ctx["limit"])
  247. query += query_limit
  248. res["logical_card_ids"] = []
  249. if n_search > 0:
  250. cursor.execute(query, field_vals)
  251. rows = cursor.fetchall()
  252. for row in rows:
  253. res["logical_card_ids"].append(row[0])
  254. db.commit()
  255. return res
  256. def User(db, ctx):
  257. user_fields = USER_FIELDS.copy()
  258. res = {}
  259. cursor = db.cursor()
  260. fields = user_fields.copy()
  261. user_vals = []
  262. userid = -1
  263. if "userid" in ctx: userid = ctx["userid"]
  264. if (ctx["action"] == "get"):
  265. query = "select " + ",".join(user_fields) + " from users where userid = %s"
  266. cursor.execute(query, [userid])
  267. row = cursor.fetchone()
  268. if row is not None:
  269. res["userid"] = userid
  270. for idx,f in enumerate(user_fields):
  271. if isinstance(row[idx], datetime.datetime):
  272. res[f] = row[idx].strftime("%Y-%M-%d %H:%m:%S")
  273. else:
  274. res[f] = row[idx]
  275. else:
  276. res["api_comment"] = "user not found"
  277. elif (ctx["action"] == "add"):
  278. fields.append("active")
  279. fields.append("created")
  280. for f in user_fields:
  281. if f in ctx: user_vals.append(ctx[f])
  282. else: user_vals.append(None)
  283. user_vals.append(1)
  284. user_vals.append(time.strftime('%Y-%m-%d %H:%M:%S'))
  285. query = "insert into users (" + ",".join(fields) + ") values (" + ",".join(["%s"]*len(fields)) + ")"
  286. cursor.execute(query, user_vals)
  287. res["userid"] = cursor.lastrowid
  288. elif (ctx["action"] == "update"):
  289. update_field = []
  290. update_val = []
  291. for f in user_fields:
  292. if f in ctx:
  293. update_field.append(f + "= %s")
  294. update_val.append(ctx[f])
  295. update_val.append(userid)
  296. query = "update users set " + ",".join(update_field) + " where userid = %s"
  297. cursor.execute(query, update_val)
  298. res["userid"] = userid
  299. elif (ctx["action"] == "delete"):
  300. query = "delete from users where userid = %s"
  301. cursor.execute(query, [userid])
  302. elif (ctx["action"] == "search"):
  303. res["userids"] = []
  304. res["userid"] = userid
  305. search_field = []
  306. search_val = []
  307. for f in user_fields:
  308. if f in ctx:
  309. search_field.append(f + " like %s")
  310. search_val.append('%' + ctx[f] + '%')
  311. query_limit = " "
  312. if "limit" in ctx:
  313. query_limit = " limit %s "
  314. search_vals.append(ctx["limit"])
  315. query = "select userid from users where " + " and ".join(search_field) + query_limit
  316. cursor.execute(query, search_vals)
  317. rows = cursor.fetchall()
  318. for row in rows:
  319. res["userids"].append(row[0])
  320. db.commit()
  321. return res
  322. def main(db):
  323. print("main")
  324. print("---------")
  325. print("---------")
  326. print("---------")
  327. res = User(db, {"action":"add", "username":"abe" })
  328. print("user.add:", res)
  329. res = User(db, {"action":"update", "username":"abeabe", "userid":res["userid"]})
  330. print("user.update:", res)
  331. res = User(db, {"action":"get", "userid":res["userid"]})
  332. print("user.get:", res)
  333. res = User(db, {"action":"delete", "userid": res["userid"]})
  334. print("user.delete:", res)
  335. print("---------")
  336. print("---------")
  337. print("---------")
  338. res = Card(db, {"action":"get", "logical_card_id":1})
  339. print("card.get:", res)
  340. res = Card(db, {"action":"add", "mag_token":"2:1234", "rfid_token":"26:20:415", "comment":"testing api", "userid":1})
  341. print("card.add:", res)
  342. res = Card(db, {"action":"update", "mag_token":"2:9234", "logical_card_id":res["logical_card_id"]})
  343. print("card.update:", res)
  344. res = Card(db, {"action":"delete", "logical_card_id":res["logical_card_id"]})
  345. print("card.delete:", res)
  346. print("---------")
  347. print("---------")
  348. print("---------")
  349. res = Pass(db, {"action":"get", "user_pass_id":11})
  350. print("pass.get:", res)
  351. res = Pass(db, {"action":"add", "logical_card_id":1, "queue_order":9, "rule":"TEST-ORG-NDAY", "nday_orig":3})
  352. print("pass.add:", res)
  353. res = Pass(db, {"action":"update", "user_pass_id":res["user_pass_id"], "queue_order":10, "rule":"TEST-ORG-NDAY", "nday_orig":5})
  354. print("pass.update:", res)
  355. res = Pass(db, {"action":"delete", "user_pass_id":res["user_pass_id"]})
  356. print("pass.delete:", res)
  357. print("---------")
  358. print("---------")
  359. print("---------")
  360. res = UserInfo(db, {"userid":348})
  361. print("userinfo:", json.dumps(res, indent=2))
  362. print("---------")
  363. print("---------")
  364. print("---------")
  365. res = Request({"function":"CardInfo", "action":"search", "logical_card_id":1})
  366. print("request.card.search:", res)
  367. if __name__ == "__main__":
  368. conn = mysql.connector.connect(user=_USER, password=_PASSWORD, host=_HOST, database=_DATABASE, port=_PORT)
  369. main(conn)
  370. conn.close()