server_controller.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import json
  2. from datetime import timedelta
  3. from time import strptime
  4. from bottle import request, response
  5. import model
  6. from debug import debug
  7. from passlib.hash import sha256_crypt
  8. from util import salt
  9. def missing_attributes(attributes):
  10. for attr in attributes:
  11. if attr not in request.json or request.json[attr] == '' or request.json[attr] is None:
  12. if str(attr) == 'session_id':
  13. return 'You are not signed in.'
  14. return 'Missing value for attribute ' + str(attr)
  15. if str(attr) == 'session_id':
  16. if not model.valid_session_id(request.json['session_id']):
  17. return 'You are not signed in.'
  18. return False
  19. def login():
  20. missing = missing_attributes(['username', 'password'])
  21. if missing:
  22. return bad_request(missing)
  23. username = request.json['username']
  24. password = request.json['password']
  25. session_id = model.login(username, password)
  26. if session_id:
  27. return {'session_id': session_id}
  28. else:
  29. return forbidden('Invalid login data')
  30. def depot():
  31. missing = missing_attributes(['session_id'])
  32. if missing:
  33. return bad_request(missing)
  34. user_id = model.get_user_id_by_session_id(request.json['session_id'])
  35. return {'data': model.get_user_ownership(user_id),
  36. 'own_wealth': model.user_wealth(user_id)}
  37. def register():
  38. missing = missing_attributes(['username', 'password'])
  39. if missing:
  40. return bad_request(missing)
  41. username = request.json['username'].strip()
  42. if username == '':
  43. return bad_request('Username can not be empty.')
  44. hashed_password = sha256_crypt.encrypt(request.json['password'] + salt)
  45. if model.user_exists(username):
  46. return bad_request('User already exists.')
  47. game_key = ''
  48. if 'game_key' in request.json:
  49. game_key = request.json['game_key'].strip().upper()
  50. if game_key != '' and game_key not in model.unused_keys():
  51. return bad_request('Game key is not valid.')
  52. if model.register(username, hashed_password, game_key):
  53. return {'message': "successfully registered user"}
  54. else:
  55. return bad_request('registration not successful')
  56. def activate_key():
  57. missing = missing_attributes(['key', 'session_id'])
  58. if missing:
  59. return bad_request(missing)
  60. if model.valid_key(request.json['key']):
  61. user_id = model.get_user_id_by_session_id(request.json['session_id'])
  62. model.activate_key(request.json['key'], user_id)
  63. return {'message': "successfully activated key"}
  64. else:
  65. return bad_request('Invalid key.')
  66. def order():
  67. missing = missing_attributes(['buy', 'session_id', 'amount', 'ownable', 'time_until_expiration'])
  68. if missing:
  69. return bad_request(missing)
  70. if not model.ownable_name_exists(request.json['ownable']):
  71. return bad_request('This kind of object can not be ordered.')
  72. buy = request.json['buy']
  73. sell = not buy
  74. session_id = request.json['session_id']
  75. amount = request.json['amount']
  76. try:
  77. amount = int(amount)
  78. except ValueError:
  79. return bad_request('Invalid amount.')
  80. if amount < 0:
  81. return bad_request('You can not order a negative amount.')
  82. if amount < 1:
  83. return bad_request('The minimum order size is 1.')
  84. ownable_name = request.json['ownable']
  85. time_until_expiration = float(request.json['time_until_expiration'])
  86. if time_until_expiration < 0:
  87. return bad_request('Invalid expiration time.')
  88. ownable_id = model.ownable_id_by_name(ownable_name)
  89. user_id = model.get_user_id_by_session_id(session_id)
  90. model.own(user_id, ownable_name)
  91. ownership_id = model.get_ownership_id(ownable_id, user_id)
  92. try:
  93. if request.json['limit'] == '':
  94. limit = None
  95. elif request.json['limit'] is None:
  96. limit = None
  97. else:
  98. limit = float(request.json['limit'])
  99. except ValueError: # for example when float fails
  100. limit = None
  101. except KeyError: # for example when limit was not specified
  102. limit = None
  103. try:
  104. if request.json['stop_loss'] == '':
  105. stop_loss = None
  106. elif request.json['stop_loss'] is None:
  107. stop_loss = None
  108. else:
  109. stop_loss = 'stop_loss' in request.json and request.json['stop_loss']
  110. if stop_loss is not None and limit is None:
  111. return bad_request('Can only set stop-loss for limit orders')
  112. except KeyError: # for example when stop_loss was not specified
  113. stop_loss = None
  114. if sell:
  115. if not model.user_owns_at_least(amount, user_id, ownable_id):
  116. return bad_request('You can not sell more than you own.')
  117. try:
  118. expiry = strptime(model.current_db_time(), '%Y-%m-%d %H:%M:%S') + timedelta(minutes=time_until_expiration)
  119. except OverflowError:
  120. return bad_request('The expiration time is too far in the future.')
  121. model.place_order(buy, ownership_id, limit, stop_loss, amount, expiry)
  122. return {'message': "Order placed."}
  123. def gift():
  124. missing = missing_attributes(['session_id', 'amount', 'object_name', 'username'])
  125. if missing:
  126. return bad_request(missing)
  127. if not model.ownable_name_exists(request.json['object_name']):
  128. return bad_request('This kind of object can not be given away.')
  129. if request.json['username'] == 'bank' or not model.user_exists(request.json['username']):
  130. return bad_request('There is no user with this name.')
  131. try:
  132. amount = float(request.json['amount'])
  133. except ValueError:
  134. return bad_request('Invalid amount.')
  135. ownable_id = model.ownable_id_by_name(request.json['object_name'])
  136. sender_id = model.get_user_id_by_session_id(request.json['session_id'])
  137. recipient_id = model.get_user_id_by_name(request.json['username'])
  138. if not model.user_owns_at_least(amount, sender_id, ownable_id):
  139. amount = model.available_amount(sender_id, ownable_id)
  140. model.send_ownable(sender_id, recipient_id, request.json['object_name'], amount)
  141. return {'message': "Gift sent."}
  142. def orders():
  143. missing = missing_attributes(['session_id'])
  144. if missing:
  145. return bad_request(missing)
  146. data = model.get_user_orders(model.get_user_id_by_session_id(request.json['session_id']))
  147. return {'data': data}
  148. def orders_on():
  149. missing = missing_attributes(['session_id', 'ownable'])
  150. if missing:
  151. return bad_request(missing)
  152. if not model.ownable_name_exists(request.json['ownable']):
  153. return bad_request('This kind of object can not be ordered.')
  154. user_id = model.get_user_id_by_session_id(request.json['session_id'])
  155. ownable_id = model.ownable_id_by_name(request.json['ownable'])
  156. data = model.get_ownable_orders(user_id, ownable_id)
  157. return {'data': data}
  158. def cancel_order():
  159. missing = missing_attributes(['session_id', 'order_id'])
  160. if missing:
  161. return bad_request(missing)
  162. if not model.user_has_order_with_id(request.json['session_id'], request.json['order_id']):
  163. return bad_request('You do not have an order with that number.')
  164. model.delete_order(request.json['order_id'])
  165. return {'message': "Successfully deleted order"}
  166. def change_password():
  167. missing = missing_attributes(['session_id', 'password'])
  168. if missing:
  169. return bad_request(missing)
  170. hashed_password = sha256_crypt.encrypt(request.json['password'] + salt)
  171. model.change_password(request.json['session_id'], hashed_password)
  172. model.sign_out_user(request.json['session_id'])
  173. return {'message': "Successfully changed password"}
  174. def news():
  175. return {'data': model.news()}
  176. def tradables():
  177. return {'data': model.ownables()}
  178. def transactions():
  179. missing = missing_attributes(['session_id', 'ownable', 'limit'])
  180. if missing:
  181. return bad_request(missing)
  182. if not model.ownable_name_exists(request.json['ownable']):
  183. return bad_request('This kind of object can not have transactions.')
  184. return {'data': model.transactions(model.ownable_id_by_name(request.json['ownable']), request.json['limit'])}
  185. def leaderboard():
  186. return {'data': model.leaderboard()}
  187. def not_found(msg=''):
  188. response.status = 404
  189. if debug:
  190. msg = str(response.status) + ': ' + msg
  191. response.content_type = 'application/json'
  192. return json.dumps({"error_message": msg})
  193. def forbidden(msg=''):
  194. response.status = 403
  195. if debug:
  196. msg = str(response.status) + ': ' + msg
  197. response.content_type = 'application/json'
  198. return json.dumps({"error_message": msg})
  199. def bad_request(msg=''):
  200. response.status = 400
  201. if debug:
  202. msg = str(response.status) + ': ' + msg
  203. response.content_type = 'application/json'
  204. return json.dumps({"error_message": msg})