PopufareAPI.py 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114
  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. import hashlib
  27. #conn = mysql.connector.connect(user='bus', password='bus', host='localhost', database='busdb', port=3306)
  28. _USER = 'busapi'
  29. _PASSWORD = 'bus'
  30. _HOST = 'localhost'
  31. _DATABASE = 'busdb'
  32. _PORT = 5506
  33. Function = [
  34. "User",
  35. "Card",
  36. "Pass",
  37. "Log",
  38. "PricePoints",
  39. "AdminGetCard", "AdminGetCards", "AdminGetPass", "AdminGetUser",
  40. "AdminGetAdmin", "AdminGetPassesOnCard", "AdminGetPendingQueue", "AdminProcessPendingQueue",
  41. "AdminRemovePendingQueue", "AdminCreateCardBlock", "AdminCreateCard", "AdminSetUser",
  42. "AdminSetAdmin", "AdminAddPass", "AdminAddCard", "AdminAddUser",
  43. "AdminAddAdmin", "AdminRemovePass", "AdminRemovePasses", "AdminRemoveCard",
  44. "AdminRemoveUser", "AdminRemoveAdmin", "AdminTransferCard", "AdminTransferPass",
  45. "AdminGetPassOptions", "AdminAddCardToUser", "AdminRemoveCardFromUser", "AdminGetAdminPermissions",
  46. "AdminAddAdminPermissions", "AdminRemoveAdminPermissions", "AdminAddAdminApiPermissions", "AdminRemoveAdminApiPermissions",
  47. "AdminSetAdminApiPermissions", "AdminGetCustomCard", "AdminGetAdmins", "AdminSearchCards",
  48. "AdminSearchUsers", "AdminSearchAdmins"]
  49. PASS_FIELDS = ["logical_card_id", "issued", "activated", "deactivated", "firstused", "lastused",
  50. "nrides_orig", "nrides_remain", "nday_orig", "nday_expiration",
  51. "active", "expired", "queue_order",
  52. "rule", "comment", "paytype" ]
  53. CARD_FIELDS = ["mag_token", "rfid_token", "comment", "userid", "issued", "deactivated", "lastused",
  54. "firstused", "group_id", "issuetype"]
  55. USER_FIELDS = ["username", "comment", "first_name", "last_name", "phone",
  56. "email", "address", "city", "state", "zip", "passwordhash",
  57. "shipping_address", "shipping_city", "shipping_state", "shipping_zip",
  58. "shipping_name", "shipping_country_code", "shipping_country_name"]
  59. GROUP_FIELDS = ["id", "group_id", "group_name"]
  60. RULECLASS_FIELDS = ["id", "group_id", "group_name"]
  61. def Request(ctx):
  62. _conn = mysql.connector.connect(user=_USER, password=_PASSWORD, host=_HOST, database=_DATABASE, port=_PORT)
  63. res = {}
  64. if "function" in ctx:
  65. if ctx["function"] == "CardInfo":
  66. res = CardInfo(_conn, ctx)
  67. elif ctx["function"] == "UserInfo":
  68. res = UserInfo(_conn, ctx)
  69. elif ctx["function"] == "User":
  70. res = User(_conn, ctx)
  71. elif ctx["function"] == "Card":
  72. res = Card(_conn, ctx)
  73. elif ctx["function"] == "Pass":
  74. res = Pass(_conn, ctx)
  75. elif ctx["function"] == "Group":
  76. res = Group(_conn, ctx)
  77. elif ctx["function"] == "Ruleclass":
  78. res = Ruleclass(_conn, ctx)
  79. elif ctx["function"] == "RecycleCard":
  80. res = RecycleCard(_conn, ctx)
  81. elif ctx["function"] == "AddCardBlock":
  82. res = AddCardBlock(_conn, ctx)
  83. elif ctx["function"] == "Search":
  84. res = Search(_conn, ctx)
  85. _conn.close()
  86. return res
  87. ## _ _ __
  88. ## ___ __ _ _ __ __| (_)_ __ / _| ___
  89. ## / __/ _` | '__/ _` | | '_ \| |_ / _ \
  90. ## | (_| (_| | | | (_| | | | | | _| (_) |
  91. ## \___\__,_|_| \__,_|_|_| |_|_| \___/
  92. ##
  93. def CardInfo(db, ctx):
  94. card_res = {}
  95. action = "get"
  96. if "action" in ctx:
  97. action = ctx["action"]
  98. if action == "get":
  99. print("CardInfo:", ctx)
  100. cardid = -1
  101. if "logical_card_id" in ctx:
  102. cardid = ctx["logical_card_id"]
  103. card_res["logical_card_id"] = cardid
  104. card_res = Card(db, {"action":"get", "logical_card_id": cardid})
  105. card_res["pass"] = []
  106. if card_res["result"] == "success":
  107. ## through each of the passes on the card
  108. ##
  109. pass_query = "select user_pass_id from user_pass where logical_card_id = %s and expired = 0 order by queue_order asc"
  110. pass_cursor = db.cursor()
  111. pass_cursor.execute(pass_query, [card_res["logical_card_id"]])
  112. pass_rows = pass_cursor.fetchall()
  113. for pass_row in pass_rows:
  114. pass_res = Pass(db, {"action":"get", "user_pass_id":pass_row[0]})
  115. card_res["pass"].append(pass_res)
  116. card_res["user"] = {}
  117. if ((card_res["userid"] is not None) and (int(card_res["userid"]) >= 0)):
  118. card_res["user"] = User(db, {"action":"get", "userid": card_res["userid"] })
  119. elif action == "search":
  120. card_res["cards"] = []
  121. res_cardid = Card(db, ctx)
  122. for cid in res_cardid["logical_card_ids"]:
  123. _c = CardInfo(db, {"action":"get", "logical_card_id":cid})
  124. card_res["cards"].append(_c)
  125. card_res["result"] = "success"
  126. return card_res
  127. ## _ __
  128. ## _ _ ___ ___ _ __(_)_ __ / _| ___
  129. ## | | | / __|/ _ \ '__| | '_ \| |_ / _ \
  130. ## | |_| \__ \ __/ | | | | | | _| (_) |
  131. ## \__,_|___/\___|_| |_|_| |_|_| \___/
  132. ##
  133. def UserInfo(db, ctx):
  134. res = {}
  135. res["result"] = "fail"
  136. userid = -1
  137. if ("userid" in ctx):
  138. userid = ctx["userid"]
  139. pass_fields = PASS_FIELDS.copy()
  140. card_fields = CARD_FIELDS.copy()
  141. user_fields = USER_FIELDS.copy()
  142. res["userid"] = userid
  143. cursor = db.cursor()
  144. ## fill in user data
  145. ##
  146. res["user"] = {}
  147. fields = USER_FIELDS.copy()
  148. query = "select " + ",".join(fields) + " from users where userid = %s"
  149. cursor.execute(query, [userid])
  150. row = cursor.fetchone()
  151. if row is None:
  152. res["api_comment"] = "user not found"
  153. return res
  154. res["user"]["userid"] = userid
  155. for idx,f in enumerate(user_fields):
  156. res["user"][f] = row[idx]
  157. ## go through each card and fill in card data and pass data
  158. ##
  159. res["card"] = []
  160. query = "select logical_card_id from user_card where userid = %s and active = 1 order by logical_card_id asc"
  161. card_cursor = db.cursor()
  162. card_cursor.execute(query, [userid])
  163. rows = card_cursor.fetchall()
  164. for row in rows:
  165. card_res = CardInfo(db, {"logical_card_id":row[0]})
  166. res["card"].append(card_res)
  167. res["result"] = "success"
  168. return res
  169. def _update_pass_bits(cursor, passid):
  170. q = "select logical_card_id from user_pass where user_pass_id = %s"
  171. cursor.execute(q, [passid])
  172. rows = cursor.fetchall()
  173. print("\n\nupdating pass bits", passid, "\n\n")
  174. cardid = -1
  175. for row in rows:
  176. cardid = row[0]
  177. break
  178. print("\n\nupdating pass bits cardid:", cardid, "\n\n")
  179. if cardid < 0: return
  180. q = "update user_pass set active = 0 where logical_card_id = %s"
  181. cursor.execute(q, [cardid])
  182. q = "update user_pass set active = 1 where logical_card_id = %s and expired = 0 and queue_order = " + \
  183. "( select min(x.queue_order) from user_pass x where x.logical_card_id = %s and x.expired = 0 )"
  184. cursor.execute(q, [cardid,cardid])
  185. ## _ _
  186. ## _ __ _ _| | ___ ___| | __ _ ___ ___
  187. ## | '__| | | | |/ _ \/ __| |/ _` / __/ __|
  188. ## | | | |_| | | __/ (__| | (_| \__ \__ \
  189. ## |_| \__,_|_|\___|\___|_|\__,_|___/___/
  190. ##
  191. def Ruleclass(db, ctx):
  192. res = {}
  193. ruleclass_fields = RULECLASS_FIELDS.copy()
  194. cursor = db.cursor()
  195. fields = ruleclass_fields.copy()
  196. field_vals = []
  197. if ctx["action"] == "search":
  198. query = "select id, rulename, ruleclass from rule_class"
  199. cursor.execute(query)
  200. rows = cursor.fetchall()
  201. res["ruleclass"] = []
  202. for row in rows:
  203. res["ruleclass"].append({"id":row[0], "rulename":row[1], "ruleclass":row[2]})
  204. db.commit()
  205. return res
  206. ##
  207. ## _ __ __ _ ___ ___
  208. ## | '_ \ / _` / __/ __|
  209. ## | |_) | (_| \__ \__ \
  210. ## | .__/ \__,_|___/___/
  211. ## |_|
  212. def Pass(db, ctx):
  213. res = {}
  214. passid = -1
  215. if ("user_pass_id" in ctx):
  216. passid = ctx["user_pass_id"]
  217. pass_fields = PASS_FIELDS.copy()
  218. cursor = db.cursor()
  219. fields = pass_fields.copy()
  220. field_vals = []
  221. if (ctx["action"] == "get"):
  222. query = "select " + ",".join(pass_fields) + " from user_pass where user_pass_id = %s"
  223. cursor.execute(query, [passid])
  224. row = cursor.fetchone()
  225. if row is not None:
  226. res["result"] = "success"
  227. res["user_pass_id"] = passid
  228. for idx,f in enumerate(pass_fields):
  229. if isinstance(row[idx], datetime.datetime):
  230. res[f] = row[idx].strftime("%Y-%m-%d %H:%M:%S")
  231. else:
  232. res[f] = row[idx]
  233. else:
  234. res["result"] = "fail"
  235. res["api_comment"] = "pass not found"
  236. elif (ctx["action"] == "add"):
  237. if (not "logical_card_id" in ctx) or (ctx["logical_card_id"] == ''):
  238. res["result"] = "fail"
  239. res["api_comment"] = "must have logical_card_id to add pass"
  240. else:
  241. ## fill in some default values
  242. ##
  243. dt = time.strftime('%Y-%m-%d %H:%M:%S')
  244. if "issued" not in ctx: ctx["issued"] = dt
  245. if "expired" not in ctx: ctx["expired"] = 0
  246. if "active" not in ctx: ctx["active"] = 0
  247. if "logical_card_id" in ctx:
  248. cardid = ctx["logical_card_id"]
  249. _q = "select queue_order from user_pass where logical_card_id = %s and expired = 0 order by queue_order desc limit 1"
  250. _c = db.cursor()
  251. _c.execute(_q, [cardid])
  252. _r = _c.fetchone()
  253. if _r is not None:
  254. ctx["queue_order"] = int(_r[0])+1
  255. else:
  256. ctx["active"] = 1
  257. ctx["queue_order"] = 0
  258. else:
  259. ctx["queue_order"] = 0
  260. for f in pass_fields:
  261. if f in ctx: field_vals.append(ctx[f])
  262. else: field_vals.append(None)
  263. query = "insert into user_pass (" + ",".join(fields) + ") values (" + ",".join(["%s"]*len(fields)) + ")"
  264. print(query)
  265. print(fields, field_vals)
  266. cursor.execute(query, field_vals)
  267. res["user_pass_id"] = cursor.lastrowid
  268. res["result"] = "success"
  269. _update_pass_bits(cursor, passid);
  270. elif (ctx["action"] == "update"):
  271. update_field = []
  272. update_val = []
  273. for f in pass_fields:
  274. if f in ctx:
  275. update_field.append(f + "= %s")
  276. update_val.append(ctx[f])
  277. update_val.append(passid)
  278. query = "update user_pass set " + ",".join(update_field) + " where user_pass_id = %s"
  279. cursor.execute(query, update_val)
  280. res["user_pass_id"] = passid
  281. res["result"] = "success"
  282. _update_pass_bits(cursor, passid);
  283. elif (ctx["action"] == "deactivate"):
  284. update_field = []
  285. update_val = []
  286. for f in pass_fields:
  287. if f in ctx:
  288. update_field.append(f + "= %s")
  289. update_val.append(ctx[f])
  290. update_val.append(passid)
  291. query = "update user_pass set active = 0, expired = 1 where user_pass_id = %s"
  292. cursor.execute(query, [passid])
  293. _update_pass_bits(cursor, passid);
  294. res["user_pass_id"] = passid
  295. res["result"] = "success"
  296. elif (ctx["action"] == "delete"):
  297. query = "delete from user_pass where user_pass_id = %s"
  298. cursor.execute(query, [passid])
  299. _update_pass_bits(cursor, passid);
  300. res["result"] = "success"
  301. db.commit()
  302. return res
  303. ## _
  304. ## ___ __ _ _ __ __| |
  305. ## / __/ _` | '__/ _` |
  306. ## | (_| (_| | | | (_| |
  307. ## \___\__,_|_| \__,_|
  308. ##
  309. def Card(db, ctx):
  310. card_fields = CARD_FIELDS.copy()
  311. res = {}
  312. cardid = -1
  313. if ("logical_card_id" in ctx):
  314. cardid = ctx["logical_card_id"]
  315. cursor = db.cursor()
  316. fields = card_fields.copy()
  317. field_vals = []
  318. if (ctx["action"] == "get"):
  319. query = "select " + ",".join(card_fields) + " from user_card where logical_card_id = %s"
  320. cursor.execute(query, [cardid])
  321. row = cursor.fetchone()
  322. if row is not None:
  323. res["logical_card_id"] = cardid
  324. for idx,f in enumerate(card_fields):
  325. if isinstance(row[idx], datetime.datetime):
  326. res[f] = row[idx].strftime("%Y-%m-%d %H:%M:%S")
  327. else:
  328. res[f] = row[idx]
  329. res["result"] = "success"
  330. else:
  331. res["result"] = "fail"
  332. res["api_comment"] = "card not found"
  333. elif (ctx["action"] == "add"):
  334. fields.append("active")
  335. for f in card_fields:
  336. if f in ctx: field_vals.append(ctx[f])
  337. else: field_vals.append(None)
  338. field_vals.append(1)
  339. query = "insert into user_card (" + ",".join(fields) + ") values (" + ",".join(["%s"]*len(fields)) + ")"
  340. cursor.execute(query, field_vals)
  341. res["logical_card_id"] = cursor.lastrowid
  342. res["result"] = "success"
  343. elif (ctx["action"] == "update"):
  344. if not "logical_card_id" in ctx:
  345. res["result"] = "fail"
  346. res["api_comment"] = "must supply a logical_card_id"
  347. else:
  348. update_field = []
  349. update_val = []
  350. query_card_id = ctx["logical_card_id"]
  351. cursor.execute("select logical_card_id from user_card where logical_card_id = %s", [query_card_id])
  352. rows = cursor.fetchall()
  353. if len(rows) == 0:
  354. res["result"] = "fail"
  355. res["api_comment"] = "card not found"
  356. else:
  357. print(">>>>", len(rows))
  358. for row in rows:
  359. logical_card_id = row[0]
  360. for f in card_fields:
  361. if f in ctx:
  362. update_field.append(f + "= %s")
  363. update_val.append(ctx[f])
  364. update_val.append(cardid)
  365. query = "update user_card set " + ",".join(update_field) + " where logical_card_id = %s"
  366. cursor.execute(query, update_val)
  367. res["logical_card_id"] = cardid
  368. res["result"] = "success"
  369. elif (ctx["action"] == "delete"):
  370. query = "delete from user_card where logical_card_id = %s"
  371. cursor.execute(query, [cardid])
  372. res["result"] = "success"
  373. elif (ctx["action"] == "search"):
  374. query = "select logical_card_id from user_card where "
  375. n_search = 0
  376. if "logical_card_id" in ctx:
  377. query += " logical_card_id = %s"
  378. field_vals.append( ctx["logical_card_id"])
  379. n_search += 1
  380. if "mag_token" in ctx:
  381. query += " mag_token like %s "
  382. field_vals.append( '%' + ctx["mag_token"] + '%')
  383. n_search += 1
  384. if "rfid_token" in ctx:
  385. if len(field_vals)>0: query += " and "
  386. query += " rfid_token like %s "
  387. field_vals.append( '%' + ctx["rfid_token"] + '%')
  388. n_search += 1
  389. query_limit = " "
  390. if "limit" in ctx:
  391. query_limit = " limit %s "
  392. search_vals.append(ctx["limit"])
  393. query += query_limit
  394. res["logical_card_ids"] = []
  395. if n_search > 0:
  396. cursor.execute(query, field_vals)
  397. rows = cursor.fetchall()
  398. for row in rows:
  399. res["logical_card_ids"].append(row[0])
  400. res["result"] = "success"
  401. db.commit()
  402. return res
  403. ##
  404. ## __ _ _ __ ___ _ _ _ __
  405. ## / _` | '__/ _ \| | | | '_ \
  406. ## | (_| | | | (_) | |_| | |_) |
  407. ## \__, |_| \___/ \__,_| .__/
  408. ## |___/ |_|
  409. def Group(db,ctx):
  410. group_res = { "result":"fail"}
  411. action = "get"
  412. if "action" in ctx:
  413. action = ctx["action"]
  414. cursor = db.cursor()
  415. if action == "get":
  416. group_res["group"] = []
  417. query = "select group_id, group_name from groups order by group_id asc"
  418. cursor.execute(query)
  419. rows = cursor.fetchall()
  420. for row in rows:
  421. group_res["group"].append({"group_id":row[0], "group_name":row[1]})
  422. group_res["result"] = "success"
  423. elif action == "getone":
  424. group_res["group"] = []
  425. query = "select group_id, group_name from groups where group_name = %s "
  426. cursor.execute(query, [ctx["group"]])
  427. row = cursor.fetchone()
  428. if not row:
  429. group_res["result"] = "fail"
  430. group_res["api_comment"] = "invalid group"
  431. else:
  432. group_res["result"] = "success"
  433. group_res["group_id"] = row[0]
  434. elif action == "default":
  435. return Group(db, {"action":"getone", "group":"TEST-ORG"})
  436. db.commit()
  437. return group_res
  438. ##
  439. ## _ _ ___ ___ _ __
  440. ## | | | / __|/ _ \ '__|
  441. ## | |_| \__ \ __/ |
  442. ## \__,_|___/\___|_|
  443. ##
  444. def User(db, ctx):
  445. user_fields = USER_FIELDS.copy()
  446. res = {}
  447. cursor = db.cursor()
  448. fields = user_fields.copy()
  449. user_vals = []
  450. userid = -1
  451. if "userid" in ctx: userid = ctx["userid"]
  452. print("cp.user")
  453. ## USER GET
  454. ##
  455. if (ctx["action"] == "get"):
  456. query = "select " + ",".join(user_fields) + " from users where userid = %s"
  457. cursor.execute(query, [userid])
  458. row = cursor.fetchone()
  459. if row is not None:
  460. res["userid"] = userid
  461. for idx,f in enumerate(user_fields):
  462. if isinstance(row[idx], datetime.datetime):
  463. res[f] = row[idx].strftime("%Y-%m-%d %H:%M:%S")
  464. else:
  465. res[f] = row[idx]
  466. res["result"] = "success"
  467. else:
  468. res["result"] = "fail"
  469. res["api_comment"] = "user not found"
  470. ## USER ADD
  471. ##
  472. elif (ctx["action"] == "add"):
  473. if ((not "password" in ctx) or
  474. (not "username" in ctx) ):
  475. res["api_comment"] = "invalid parameters, need username and password to create account"
  476. res["result"] = "fail"
  477. else:
  478. uname = ctx["username"]
  479. pword = ctx["password"]
  480. fields.append("active")
  481. fields.append("created")
  482. for f in user_fields:
  483. if f in ctx: user_vals.append(ctx[f])
  484. elif f == "passwordhash":
  485. ha = hashlib.sha256()
  486. ha.update(str.encode(uname))
  487. ha.update(str.encode(pword))
  488. user_vals.append(ha.hexdigest())
  489. else: user_vals.append(None)
  490. user_vals.append(1)
  491. user_vals.append(time.strftime('%Y-%m-%d %H:%M:%S'))
  492. query = "insert into users (" + ",".join(fields) + ") values (" + ",".join(["%s"]*len(fields)) + ")"
  493. cursor.execute(query, user_vals)
  494. res["userid"] = cursor.lastrowid
  495. res["result"] = "success"
  496. ## USER UPDATE
  497. ##
  498. elif (ctx["action"] == "update"):
  499. if not "userid" in ctx:
  500. res["result"] = "fail"
  501. res["api_comment"] = "no userid specified"
  502. else:
  503. uname = ''
  504. query = "select username from users where userid = %s";
  505. cursor.execute(query, [userid])
  506. rows = cursor.fetchall()
  507. for row in rows:
  508. uname = row[0]
  509. if uname == '':
  510. res["result"] = "fail"
  511. res["api_comment"] = "could not find username"
  512. else:
  513. update_field = []
  514. update_val = []
  515. print("user_field:", user_fields)
  516. print("ctx:", ctx)
  517. for f in user_fields:
  518. if (f == "passwordhash") and ("password" in ctx):
  519. update_field.append(" passwordhash = %s ")
  520. ha = hashlib.sha256()
  521. ha.update(str.encode(uname))
  522. ha.update(str.encode(ctx["password"]))
  523. update_val.append(ha.hexdigest())
  524. elif f in ctx:
  525. update_field.append(f + "= %s")
  526. update_val.append(ctx[f])
  527. else:
  528. pass
  529. #update_val.append(None)
  530. update_val.append(userid)
  531. if len(update_field) == 0:
  532. print("NOPE")
  533. print("manage_user.update>>>", userid, ":".join(update_field), ":".join(update_val), len(update_field))
  534. query = "update users set " + ",".join(update_field) + " where userid = %s"
  535. print("WTFFF???", query)
  536. cursor.execute(query, update_val)
  537. res["userid"] = userid
  538. res["result"] = "success"
  539. ## USER DELETE
  540. ##
  541. elif (ctx["action"] == "delete"):
  542. query = "delete from users where userid = %s"
  543. cursor.execute(query, [userid])
  544. ## USER SEARCH
  545. ##
  546. elif (ctx["action"] == "search"):
  547. res["userids"] = []
  548. res["userid"] = userid
  549. res["result"] = "success"
  550. search_field = []
  551. search_val = []
  552. for f in user_fields:
  553. if f in ctx:
  554. search_field.append(f + " like %s")
  555. search_val.append('%' + ctx[f] + '%')
  556. query_limit = " "
  557. if "limit" in ctx:
  558. query_limit = " limit %s "
  559. search_val.append(ctx["limit"])
  560. query = "select userid from users where " + " and ".join(search_field) + query_limit
  561. cursor.execute(query, search_val)
  562. rows = cursor.fetchall()
  563. for row in rows:
  564. res["userids"].append(row[0])
  565. db.commit()
  566. return res
  567. ## _ _
  568. ## _ __ ___ ___ _ _ ___| | ___ ___ __ _ _ __ __| |
  569. ## | '__/ _ \/ __| | | |/ __| |/ _ \ / __/ _` | '__/ _` |
  570. ## | | | __/ (__| |_| | (__| | __/ | (_| (_| | | | (_| |
  571. ## |_| \___|\___|\__, |\___|_|\___| \___\__,_|_| \__,_|
  572. ## |___/
  573. def RecycleCard(db, ctx):
  574. res = {"result":"fail"}
  575. cursor = db.cursor()
  576. fields = ["logical_card_id", "rfid_token", "mag_token", "group",
  577. "userid",
  578. "rule", "pass_class", "nrides_remain", "nrides_orig", "nday_orig" ]
  579. val = {}
  580. for f in fields:
  581. if f in ctx:
  582. if ctx[f] and len(ctx[f]) > 0:
  583. val[f] = ctx[f]
  584. if ((not ("logical_card_id" in val)) and
  585. (not ("rfid_token" in val)) and
  586. (not ("mag_token" in val))):
  587. return res
  588. logical_card_id = -1
  589. if not ("logical_card_id" in val):
  590. if "mag_token" in val:
  591. query = "select logical_card_id from user_card where mag_token = %s and active = 1"
  592. cursor.execute(query, [val["mag_token"]])
  593. cid = cursor.fetchone()
  594. if cid is not None:
  595. val["logical_card_id"] = cid[0]
  596. else:
  597. return res
  598. elif "rfid_token" in val:
  599. query = "select logical_card_id from user_card where rfid_token = %s and active = 1"
  600. cursor.execute(query, [val["rfid_token"]])
  601. cid = cursor.fetchone()
  602. if cid is not None:
  603. val["logical_card_id"] = cid[0]
  604. else:
  605. return res
  606. group_info = Group(db, {"action":"default"})
  607. if "group" in val:
  608. group_info = Group(db, {"action":"getone", "group":val["group"]})
  609. if group_info["result"] != "success":
  610. res["api_comment"] = "invalid group"
  611. return res
  612. query = "update user_card set active = 0 where logical_card_id = %s"
  613. cursor.execute(query, [val["logical_card_id"]])
  614. card_info = {"action":"add", "group_id":group_info["group_id"], "active":1}
  615. if "mag_token" in val: card_info["mag_token"] = val["mag_token"]
  616. if "rfid_token" in val: card_info["rfid_token"] = val["rfid_token"]
  617. card_res = Card(db, card_info)
  618. if card_res["result"] != "success":
  619. res["result"] = "fail"
  620. res["api_comment"] = "failed to find card"
  621. return res
  622. res["logical_card_id"] = card_res["logical_card_id"]
  623. if "pass_class" in val:
  624. pass_opt = {"action":"add", "logical_card_id": res["logical_card_id"] }
  625. if val["pass_class"] == "OTHER":
  626. pass_opt["rule"] = val["rule"]
  627. Pass(db, pass_opt)
  628. elif val["pass_class"] == "NRIDE":
  629. pass_opt["rule"] = val["rule"]
  630. pass_opt["nrides_orig"] = val["nrides_orig"]
  631. pass_opt["nrides_remain"] = val["nrides_remain"]
  632. Pass(db, pass_opt)
  633. elif val["pass_class"] == "NDAY":
  634. pass_opt["rule"] = val["rule"]
  635. pass_opt["nday_orig"] = val["nday_orig"]
  636. Pass(db, pass_opt)
  637. return res
  638. ## _
  639. ## ___ ___ __ _ _ __ ___| |__
  640. ## / __|/ _ \/ _` | '__/ __| '_ \
  641. ## \__ \ __/ (_| | | | (__| | | |
  642. ## |___/\___|\__,_|_| \___|_| |_|
  643. ##
  644. def Search(db, ctx):
  645. res = {"result":"fail"}
  646. cursor = db.cursor()
  647. fields = ["search_type", "search_string", "start", "count"]
  648. start = "0"
  649. count = "100"
  650. val = {}
  651. for f in fields:
  652. if f in ctx:
  653. if ctx[f] and len(ctx[f]) > 0:
  654. val[f] = ctx[f]
  655. if "start" in val: start = val["start"]
  656. if "count" in val: count = val["count"]
  657. if val["search_type"] == "card":
  658. t = val["search_string"]
  659. p = '%' + t + '%'
  660. query = "select logical_card_id, mag_token, rfid_token, userid, issued, firstused, lastused, group_id, issuetype"
  661. query += " from user_card where mag_token like %s "
  662. query += " or rfid_token like %s "
  663. query += " or comment like %s "
  664. query += " or issuetype like %s "
  665. query += " and active = 1 "
  666. query += " order by logical_card_id desc"
  667. query += " limit %s,%s "
  668. _v = [p,p, p, p, int(start), int(start) + int(count)]
  669. #cursor.execute(query, [p, p, p, p])
  670. cursor.execute(query, _v)
  671. rows = cursor.fetchall()
  672. res["data"] = []
  673. for row in rows:
  674. _d = {
  675. "iscard": 1,
  676. "logical_card_id": row[0],
  677. "mag_token": row[1],
  678. "rfid_token": row[2],
  679. "userid": row[3],
  680. "issued": row[4],
  681. "firstused": row[5],
  682. "lastused": row[6],
  683. "group_id": row[7],
  684. "issuetype": row[8]
  685. }
  686. res["data"].append( _d )
  687. res["result"] = "success"
  688. elif val["search_type"] == "user":
  689. t = val["search_string"]
  690. p = '%' + t + '%'
  691. fields = [ "username", "first_name", "last_name", "phone", "email", "address", "city","state", "zip", "created",
  692. "shipping_address", "shipping_city", "shipping_state", "shipping_zip", "shipping_name",
  693. "shipping_country_code", "shipping_country_name" ]
  694. query = "select userid, " + ", ".join(fields)
  695. query += " from users "
  696. query += " where " + " like %s or ".join(fields) + " like %s "
  697. query += " and active = 1 "
  698. query += " order by userid desc"
  699. query += " limit %s,%s "
  700. print("user query:", query)
  701. _v = [p]*len(fields)
  702. _v.append(int(start))
  703. _v.append(int(start) + int(count))
  704. #cursor.execute(query, [p]*len(fields))
  705. cursor.execute(query, _v)
  706. rows = cursor.fetchall()
  707. res["data"] = []
  708. for row in rows:
  709. _d = { "userid": row[0], "isuser": 1 }
  710. for idx,f in enumerate(fields):
  711. _d[f] = row[idx+1]
  712. res["data"].append( _d )
  713. res["result"] = "success"
  714. elif val["search_type"] == "admin":
  715. t = val["search_string"]
  716. p = '%' + t + '%'
  717. fields = [ "username", "comment" ]
  718. query = "select userid, group_id, " + ", ".join(fields)
  719. query += " from admins "
  720. query += " where " + " like %s or ".join(fields) + " like %s "
  721. query += " and active = 1 "
  722. query += " order by userid desc"
  723. query += " limit %s,%s "
  724. print("user query:", query)
  725. _v = [p]*len(fields)
  726. _v.append(int(start))
  727. _v.append(int(start) + int(count))
  728. cursor.execute(query, _v)
  729. rows = cursor.fetchall()
  730. res["data"] = []
  731. for row in rows:
  732. _d = { "userid": row[0], "group_id": row[1], "isadmin": 1 }
  733. for idx,f in enumerate(fields):
  734. _d[f] = row[idx+2]
  735. res["data"].append( _d )
  736. res["result"] = "success"
  737. return res
  738. ## _ _ _ _ _ _
  739. ## __ _ __| | __| | ___ __ _ _ __ __| | | |__ | | ___ ___| | __
  740. ## / _` |/ _` |/ _` | / __/ _` | '__/ _` | | '_ \| |/ _ \ / __| |/ /
  741. ## | (_| | (_| | (_| | | (_| (_| | | | (_| | | |_) | | (_) | (__| <
  742. ## \__,_|\__,_|\__,_| \___\__,_|_| \__,_| |_.__/|_|\___/ \___|_|\_\
  743. ##
  744. def AddCardBlock(db, ctx):
  745. res = {"result":"fail"}
  746. cursor = db.cursor()
  747. fields = ["mag_token", "rfid_token", "group_id",
  748. "rule", "nday_orig", "nrides_remain", "nrides_orig",
  749. "count",
  750. "pass_rule", "pass_nrides_remain", "pass_nrides_orig",
  751. "pass_nday_orig", "pass_class"]
  752. val = {}
  753. for f in fields:
  754. if f in ctx:
  755. if ctx[f] and len(ctx[f]) > 0:
  756. val[f] = ctx[f]
  757. if not ("count" in val):
  758. res["result"] = "fail"
  759. res["api_comment"] = "count must be positive"
  760. return res
  761. if ((not ("mag_token" in val)) and
  762. (not ("rfid_token" in val))):
  763. res["result"] = "fail"
  764. res["api_comment"] = "mag_token and/or rfid_token must be specified"
  765. return res
  766. use_mag = False
  767. use_rfid = False
  768. if "mag_token" in val:
  769. use_mag = True
  770. pfx_mag_cred = val["mag_token"].split(":")[0]
  771. base_mag_cred = int(val["mag_token"].split(":")[-1])
  772. if "rfid_token" in val:
  773. use_rfid = True
  774. pfx_rfid_cred = ":".join(val["rfid_token"].split(":")[0:2])
  775. base_rfid_cred = int(val["rfid_token"].split(":")[-1])
  776. logical_card_ids = []
  777. for idx in range(int(val["count"])):
  778. card_info = {"action":"add", "group_id":val["group_id"], "active":1}
  779. if "mag_token" in val: card_info["mag_token"] = val["mag_token"]
  780. if "rfid_token" in val: card_info["rfid_token"] = val["rfid_token"]
  781. if use_mag:
  782. card_info["mag_token"] = pfx_mag_cred + ":" + str(base_mag_cred + idx)
  783. if use_rfid:
  784. card_info["rfid_token"] = pfx_rfid_cred + ":" + str(base_rfid_cred + idx)
  785. card_res = Card(db, card_info)
  786. if card_res["result"] != "success":
  787. res["result"] = "fail"
  788. res["api_comment"] = "failed to add card"
  789. return res
  790. logical_card_id = card_res["logical_card_id"]
  791. if "pass_rule" in val:
  792. pass_info = {"action":"add", "logical_card_id":logical_card_id, "active":1,
  793. "rule" : val["pass_rule"] }
  794. if val["pass_class"] == "OTHER":
  795. pass
  796. elif val["pass_class"] == "NRIDE":
  797. pass_info["nrides_remain"] = val["pass_nrides_remain"]
  798. pass_info["nrides_orig"] = val["pass_nrides_orig"]
  799. elif val["pass_class"] == "NDAY":
  800. pass_info["nday_orig"] = val["pass_nday_orig"]
  801. pass_res = Pass(db, pass_info)
  802. logical_card_ids.append(logical_card_id)
  803. res["result"] = "success"
  804. res["logical_card_ids"] = logical_card_ids
  805. return res
  806. ## _
  807. ## _ __ ___ __ _(_)_ __
  808. ## | '_ ` _ \ / _` | | '_ \
  809. ## | | | | | | (_| | | | | |
  810. ## |_| |_| |_|\__,_|_|_| |_|
  811. ##
  812. def main(db):
  813. print("main")
  814. print("---------")
  815. print("---------")
  816. print("---------")
  817. res = User(db, {"action":"add", "username":"abe" })
  818. print("user.add:", res)
  819. res = User(db, {"action":"update", "username":"abeabe", "userid":res["userid"]})
  820. print("user.update:", res)
  821. res = User(db, {"action":"get", "userid":res["userid"]})
  822. print("user.get:", res)
  823. res = User(db, {"action":"delete", "userid": res["userid"]})
  824. print("user.delete:", res)
  825. print("---------")
  826. print("---------")
  827. print("---------")
  828. res = Card(db, {"action":"get", "logical_card_id":1})
  829. print("card.get:", res)
  830. res = Card(db, {"action":"add", "mag_token":"2:1234", "rfid_token":"26:20:415", "comment":"testing api", "userid":1})
  831. print("card.add:", res)
  832. res = Card(db, {"action":"update", "mag_token":"2:9234", "logical_card_id":res["logical_card_id"]})
  833. print("card.update:", res)
  834. res = Card(db, {"action":"delete", "logical_card_id":res["logical_card_id"]})
  835. print("card.delete:", res)
  836. print("---------")
  837. print("---------")
  838. print("---------")
  839. res = Pass(db, {"action":"get", "user_pass_id":11})
  840. print("pass.get:", res)
  841. res = Pass(db, {"action":"add", "logical_card_id":1, "queue_order":9, "rule":"TEST-ORG-NDAY", "nday_orig":3})
  842. print("pass.add:", res)
  843. res = Pass(db, {"action":"update", "user_pass_id":res["user_pass_id"], "queue_order":10, "rule":"TEST-ORG-NDAY", "nday_orig":5})
  844. print("pass.update:", res)
  845. res = Pass(db, {"action":"delete", "user_pass_id":res["user_pass_id"]})
  846. print("pass.delete:", res)
  847. print("---------")
  848. print("---------")
  849. print("---------")
  850. res = UserInfo(db, {"userid":348})
  851. print("userinfo:", json.dumps(res, indent=2))
  852. print("---------")
  853. print("---------")
  854. print("---------")
  855. res = Request({"function":"CardInfo", "action":"search", "logical_card_id":1})
  856. print("request.card.search:", res)
  857. if __name__ == "__main__":
  858. conn = mysql.connector.connect(user=_USER, password=_PASSWORD, host=_HOST, database=_DATABASE, port=_PORT)
  859. main(conn)
  860. conn.close()