model.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. import random
  2. import re
  3. import sqlite3 as db
  4. import sys
  5. import uuid
  6. import db_setup
  7. from game import CURRENCY_NAME
  8. from util import debug, chars
  9. connection = None
  10. cursor = None
  11. db_name = None
  12. def query_save_name():
  13. global db_name
  14. if debug:
  15. db_name = 'test.db'
  16. return
  17. while True:
  18. save_name = input('Name of the savegame: ')
  19. if re.match(r"[A-Za-z0-9.-]{0,50}", save_name):
  20. db_name = save_name + '.db'
  21. return
  22. else:
  23. print('Must match "[A-Za-z0-9.-]{0,50}"')
  24. def connect(reconnect=False):
  25. global connection
  26. global cursor
  27. global db_name
  28. if reconnect:
  29. connection.commit()
  30. connection.close()
  31. cursor = None
  32. connection = None
  33. db_name = None
  34. if connection is None or cursor is None:
  35. query_save_name()
  36. try:
  37. connection = db.connect(db_name)
  38. cursor = connection.cursor()
  39. except db.Error as e:
  40. print("Database error %s:" % e.args[0])
  41. sys.exit(1)
  42. # finally:
  43. # if con is not None:
  44. # con.close()
  45. def setup():
  46. connect()
  47. db_setup.setup(cursor)
  48. connection.commit()
  49. def login(username, password):
  50. connect()
  51. # do not allow login as bank
  52. if password == '':
  53. return None
  54. cursor.execute('''
  55. SELECT rowid
  56. FROM users
  57. WHERE username = ?
  58. AND password = ?
  59. ''', (username, password))
  60. user_id = cursor.fetchone()
  61. if user_id:
  62. return new_session(user_id)
  63. else:
  64. return None
  65. def register(username, password, game_key):
  66. connect()
  67. if username == '':
  68. return False
  69. if password == '':
  70. return False
  71. cursor.execute('''
  72. INSERT INTO users
  73. (username, password)
  74. VALUES (? , ?)
  75. ''', (username, password))
  76. own(get_user_id_by_name(username), CURRENCY_NAME)
  77. if game_key != '':
  78. if valid_key(game_key):
  79. activate_key(game_key, get_user_id_by_name(username))
  80. return True
  81. def own(user_id, ownable_name):
  82. cursor.execute('''
  83. WITH one_ownable_id AS (SELECT rowid FROM ownables WHERE name = ?),
  84. one_user_id AS (SELECT ?)
  85. INSERT INTO ownership (user_id, ownable_id)
  86. SELECT *
  87. FROM one_user_id, one_ownable_id
  88. WHERE NOT EXISTS (
  89. SELECT * FROM ownership
  90. WHERE ownership.user_id IN one_user_id
  91. AND ownership.ownable_id IN one_ownable_id
  92. )
  93. ''', (ownable_name, user_id,))
  94. def send_ownable(from_user_id, to_user_id, ownable_name, amount):
  95. connect()
  96. if amount < 0:
  97. return False
  98. if from_user_id != bank_id():
  99. cursor.execute('''
  100. UPDATE ownership
  101. SET amount = amount - ?
  102. WHERE user_id = ?
  103. AND ownable_id = (SELECT rowid FROM ownables WHERE name = ?)
  104. ''', (amount, from_user_id, ownable_name,))
  105. if not cursor.fetchone():
  106. return False
  107. cursor.execute('''
  108. UPDATE ownership
  109. SET amount = amount + ?
  110. WHERE user_id = ?
  111. AND ownable_id = (SELECT rowid FROM ownables WHERE name = ?)
  112. ''', (amount, to_user_id, ownable_name))
  113. if cursor.rowcount == 0:
  114. return False
  115. return True
  116. def valid_key(key):
  117. connect()
  118. cursor.execute('''
  119. SELECT key
  120. FROM keys
  121. WHERE used_by_user_id IS NULL
  122. AND key = ?
  123. ''', (key,))
  124. if cursor.fetchone():
  125. return True
  126. else:
  127. return False
  128. def new_session(user_id):
  129. connect()
  130. session_id = str(uuid.uuid4())
  131. cursor.execute('''
  132. INSERT INTO SESSIONS
  133. (user_id, session_id)
  134. VALUES (? , ?)
  135. ''', (user_id[0], session_id))
  136. return session_id
  137. def save_key(key):
  138. connect()
  139. cursor.execute('''
  140. INSERT INTO keys
  141. (key)
  142. VALUES (?)
  143. ''', (key,))
  144. def drop_old_sessions():
  145. connect()
  146. # TODO: test
  147. cursor.execute('''
  148. DELETE FROM sessions s1
  149. WHERE
  150. (SELECT COUNT(*) as newer
  151. FROM sessions s2
  152. WHERE s1.user_id = s2.user_id
  153. AND s1.rowid < s2.rowid) >= 10
  154. ''')
  155. def user_exists(username):
  156. connect()
  157. cursor.execute('''
  158. SELECT rowid
  159. FROM users
  160. WHERE username = ?
  161. ''', (username,))
  162. if cursor.fetchone():
  163. return True
  164. else:
  165. return False
  166. def unused_keys():
  167. connect()
  168. cursor.execute('''
  169. SELECT key
  170. FROM keys
  171. WHERE used_by_user_id IS NULL
  172. ''')
  173. return [str(key[0]).strip().upper() for key in cursor.fetchall()]
  174. def get_user_id_by_session_id(session_id):
  175. connect()
  176. cursor.execute('''
  177. SELECT users.rowid
  178. FROM sessions, users
  179. WHERE sessions.session_id = ?
  180. AND users.rowid = sessions.user_id
  181. ''', (session_id,))
  182. ids = cursor.fetchone()
  183. if ids is None:
  184. return False
  185. return ids[0]
  186. def get_user_id_by_name(username):
  187. connect()
  188. cursor.execute('''
  189. SELECT users.rowid
  190. FROM users
  191. WHERE username = ?
  192. ''', (username,))
  193. return cursor.fetchone()[0]
  194. def get_user_ownership(user_id):
  195. connect()
  196. cursor.execute('''
  197. SELECT ownables.name, ownership.amount
  198. FROM ownership, ownables
  199. WHERE user_id = ?
  200. AND ownership.ownable_id = ownables.rowid
  201. ''', (user_id,))
  202. return cursor.fetchall()
  203. def activate_key(key, user_id):
  204. connect()
  205. cursor.execute('''
  206. UPDATE keys
  207. SET used_by_user_id = ?
  208. WHERE used_by_user_id IS NULL
  209. AND key = ?
  210. ''', (user_id, key,))
  211. if cursor.rowcount == 0:
  212. raise AssertionError
  213. send_ownable(bank_id(), user_id, CURRENCY_NAME, 1000)
  214. def bank_id():
  215. connect()
  216. cursor.execute('''
  217. SELECT users.rowid
  218. FROM users
  219. WHERE username = 'bank'
  220. ''')
  221. return cursor.fetchone()[0]
  222. def valid_session_id(session_id):
  223. connect()
  224. cursor.execute('''
  225. SELECT rowid
  226. FROM sessions
  227. WHERE session_id = ?
  228. ''', (session_id,))
  229. if cursor.fetchone():
  230. return True
  231. else:
  232. return False
  233. def get_user_orders(user_id):
  234. connect()
  235. cursor.execute('''
  236. SELECT
  237. orders.buy,
  238. ownables.name,
  239. orders.ordered_amount - orders.executed_amount,
  240. orders."limit",
  241. orders.stop_loss,
  242. orders.ordered_amount
  243. FROM orders, ownables, ownership
  244. WHERE ownership.user_id = ?
  245. AND ownership.ownable_id = ownables.rowid
  246. AND orders.ownership_id = ownership.rowid
  247. ORDER BY orders.buy, ownables.name
  248. ''', (user_id,))
  249. return cursor.fetchall()
  250. def sell_ordered_amount(user_id, ownable_id):
  251. connect()
  252. # if ownable_id == currency_id():
  253. # return 0
  254. cursor.execute('''
  255. SELECT SUM(orders.ordered_amount - orders.executed_amount)
  256. FROM orders, ownership
  257. WHERE ownership.rowid = orders.ownership_id
  258. AND ownership.user_id = ?
  259. AND ownership.ownable_id = ?
  260. AND NOT orders.buy
  261. ''', (user_id, ownable_id))
  262. return cursor.fetchone()[0]
  263. def user_owns_at_least(amount, user_id, ownable_id):
  264. connect()
  265. cursor.execute('''
  266. SELECT rowid
  267. FROM ownership
  268. WHERE user_id = ?
  269. AND ownable_id = ?
  270. AND amount - ? >= ?
  271. ''', (user_id, ownable_id, sell_ordered_amount(user_id, ownable_id), amount))
  272. if cursor.fetchone():
  273. return True
  274. else:
  275. return False
  276. def news():
  277. connect()
  278. cursor.execute('''
  279. SELECT *
  280. FROM news
  281. ORDER BY dt
  282. LIMIT 20
  283. ''')
  284. return cursor.fetchall()
  285. def ownable_name_exists(name):
  286. connect()
  287. cursor.execute('''
  288. SELECT rowid
  289. FROM ownables
  290. WHERE name = ?
  291. ''', (name,))
  292. if cursor.fetchone():
  293. return True
  294. else:
  295. return False
  296. def new_stock(name=None):
  297. connect()
  298. while name is None:
  299. name = ''.join(random.choice(chars) for _ in range(6))
  300. if ownable_name_exists(name):
  301. name = None
  302. cursor.execute('''
  303. INSERT INTO ownables(name)
  304. VALUES (?)
  305. ''', (name,))
  306. return name
  307. def new_stocks(count=1):
  308. return [new_stock() for _ in range(count)]
  309. def ownable_id_by_name(ownable_name):
  310. connect()
  311. cursor.execute('''
  312. SELECT rowid
  313. FROM ownables
  314. WHERE name = ?
  315. ''', (ownable_name,))
  316. return cursor.fetchone()[0]
  317. def get_ownership_id(ownable_id, user_id):
  318. connect()
  319. cursor.execute('''
  320. SELECT rowid
  321. FROM ownership
  322. WHERE ownable_id = ?
  323. AND user_id = ?
  324. ''', (ownable_id, user_id,))
  325. return cursor.fetchone()[0]
  326. def currency_id():
  327. connect()
  328. cursor.execute('''
  329. SELECT rowid
  330. FROM ownables
  331. WHERE name = ?
  332. ''', (CURRENCY_NAME,))
  333. return cursor.fetchone()[0]
  334. def execute_orders():
  335. connect()
  336. while True:
  337. executed_any = False
  338. # TODO execute one orders
  339. # TODO trigger stop loss orders
  340. if not executed_any:
  341. return
  342. def place_order(buy, ownership_id, limit, stop_loss, amount):
  343. connect()
  344. cursor.execute('''
  345. INSERT INTO orders
  346. (buy, ownership_id, "limit", stop_loss, ordered_amount)
  347. VALUES (?, ?, ?, ?, ?)
  348. ''', (buy, ownership_id, limit, stop_loss, amount))
  349. execute_orders()
  350. return True