server_controller.py 8.7 KB

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