DotaNoobs main site.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
11 KiB

10 years ago
10 years ago
  1. import simplejson as json
  2. from datetime import datetime, timedelta
  3. from flask.ext.sqlalchemy import SQLAlchemy
  4. from sqlalchemy.ext.mutable import Mutable
  5. import board
  6. from app import db, app
  7. from utils import parse_valve_heropedia, complete_hero_data, API_DATA
  8. # Model independant get_or_create
  9. def get_or_create_instance(session, model, **kwargs):
  10. instance = session.query(model).filter_by(**kwargs).first()
  11. if instance:
  12. return instance
  13. else:
  14. instance = model(**kwargs)
  15. session.add(instance)
  16. return instance
  17. # Get a little of that Mongoness back
  18. class Json(db.TypeDecorator):
  19. impl = db.Text
  20. def process_bind_param(self, value, dialect):
  21. if value is not None:
  22. value = json.dumps(value)
  23. return value
  24. def process_result_value(self, value, dialect):
  25. try:
  26. if value is not None:
  27. value = json.loads(value)
  28. except ValueError:
  29. return {}
  30. return value
  31. # Mongoness factor - phase 2
  32. class MutableDict(Mutable, dict):
  33. @classmethod
  34. def coerce(cls, key, value):
  35. if not isinstance(value, MutableDict):
  36. if isinstance(value, dict):
  37. return MutableDict(value)
  38. return Mutable.coerce(key,value)
  39. else:
  40. return value
  41. def __delitem__(self, key):
  42. dict.__delitem__(self, key)
  43. self.changed()
  44. def __setitem__(self, key, value):
  45. dict.__setitem__(self, key, value)
  46. self.changed()
  47. def __getstate__(self):
  48. return dict(self)
  49. def __setstate__(self, state):
  50. self.update(self)
  51. class User(db.Model):
  52. id = db.Column(db.Integer, primary_key=True)
  53. steam_id = db.Column(db.String(40), unique=True)
  54. forum_id = db.Column(db.Integer)
  55. teamspeak_id = db.Column(db.String(200), unique=True)
  56. nickname = db.Column(db.String(80))
  57. avatar = db.Column(db.String(255))
  58. bio_text = db.Column(db.String(4096))
  59. created = db.Column(db.DateTime)
  60. last_seen = db.Column(db.DateTime)
  61. twitch = db.Column(db.String(60))
  62. hitbox = db.Column(db.String(60))
  63. admin = db.Column(db.Boolean)
  64. public = db.Column(db.Boolean)
  65. logo = db.Column(db.Boolean)
  66. points_from_events = db.Column(db.Integer)
  67. points_from_ts3 = db.Column(db.Integer)
  68. points_from_forum = db.Column(db.Integer)
  69. ts3_starttime = db.Column(db.DateTime)
  70. ts3_endtime = db.Column(db.DateTime)
  71. ts3_rewardtime = db.Column(db.DateTime)
  72. ts3_stretch_award_time = db.Column(db.DateTime)
  73. ts3_longest_stretch = db.Column(db.Interval)
  74. last_post_reward = db.Column(db.Integer)
  75. winrate_data = db.Column(MutableDict.as_mutable(Json))
  76. @classmethod
  77. def get_or_create(self, steam_id):
  78. return get_or_create_instance(db.session, User, steam_id=steam_id)
  79. @classmethod
  80. def get_streaming_users(self):
  81. twitch_streams = []
  82. hitbox_streams = []
  83. for user in User.query.all():
  84. if user.points_from_events + user.points_from_ts3 + user.points_from_forum < 5: continue
  85. if user.twitch:
  86. twitch_streams.append(user.twitch)
  87. if user.hitbox:
  88. hitbox_streams.append(user.hitbox)
  89. return {'twitch': twitch_streams, 'hitbox': hitbox_streams}
  90. def __init__(self, steam_id):
  91. self.steam_id = steam_id
  92. self.az_completions = 0
  93. self.ts3_rewardtime = datetime.utcnow()
  94. self.ts3_longest_stretch = timedelta()
  95. self.created = datetime.utcnow()
  96. self.last_seen = datetime.utcnow()
  97. self.bio_text = None
  98. self.points_from_events = 0
  99. self.points_from_ts3 = 0
  100. self.points_from_forum = 0
  101. self.admin = False
  102. self.public = True
  103. self.biglogo = True
  104. def update_connection(self, reward_threshold=30):
  105. now = datetime.utcnow()
  106. self.ts3_starttime = self.ts3_starttime or now
  107. self.ts3_endtime = now
  108. # Add general TS3 points here
  109. delta = (self.ts3_endtime - self.ts3_rewardtime)
  110. duration = (delta.seconds % 3600) // 60
  111. if duration > reward_threshold:
  112. self.ts3_rewardtime = datetime.utcnow()
  113. self.points_from_ts3 += 1
  114. # Update last_seen for web profile
  115. self.last_seen = datetime.utcnow()
  116. db.session.commit();
  117. def finalize_connection(self):
  118. # Check for longest!
  119. if self.ts3_endtime and self.ts3_starttime:
  120. current_stretch = self.ts3_endtime - self.ts3_starttime
  121. if current_stretch > self.ts3_longest_stretch:
  122. self.ts3_longest_stretch = current_stretch
  123. self.ts3_stretch_award_time = datetime.utcnow()
  124. # Reset values
  125. self.ts3_starttime = None
  126. self.ts3_endtime = None
  127. db.session.commit();
  128. def update_forum_posts(self, reward_threshold=5):
  129. if self.forum_id:
  130. posts = board.Users.select().where(board.Users.id == int(self.forum_id))[0].posts
  131. if self.last_post_reward:
  132. num_points = (posts - self.last_post_reward) / reward_threshold
  133. print("Old: {0}, New: {1}, ({0} - {1}) / {2}, {3}, {4}".format(self.last_post_reward, posts, reward_threshold, num_points, self.nickname))
  134. if num_points > 0:
  135. self.points_from_forum += num_points
  136. self.last_post_reward += num_points * reward_threshold
  137. else:
  138. # Initialize if this is the first reward
  139. self.last_post_reward = posts
  140. db.session.commit()
  141. @property
  142. def is_active(self):
  143. return self.ts3_starttime and True or False
  144. def __repr__(self):
  145. return '<User {}>'.format(self.id)
  146. class TeamspeakData(db.Model):
  147. id = db.Column(db.Integer, primary_key=True)
  148. time = db.Column(db.DateTime())
  149. clients = db.Column(Json())
  150. def __init__(self, clientlist):
  151. self.time = datetime.utcnow()
  152. self.clients = clientlist
  153. class Event(db.Model):
  154. id = db.Column(db.Integer, primary_key=True)
  155. name = db.Column(db.String(200))
  156. desc = db.Column(db.String(4096))
  157. type = db.Column(db.String(20))
  158. start_time = db.Column(db.DateTime)
  159. end_time = db.Column(db.DateTime)
  160. points = db.Column(db.Integer)
  161. reward_threshold = db.Column(db.Integer)
  162. total_subchans = db.Column(db.Integer)
  163. channels = db.Column(MutableDict.as_mutable(Json))
  164. participants = db.Column(MutableDict.as_mutable(Json))
  165. def __init__(self, id):
  166. self.channels = {'event_cid':None, 'cids':[]}
  167. @classmethod
  168. def get_or_create(self, event_id):
  169. return get_or_create_instance(db.session, Event, id=event_id)
  170. @property
  171. def cids(self):
  172. return self.channels['cids']
  173. @property
  174. def event_cid(self):
  175. return self.channels['event_cid']
  176. @property
  177. def channel_ids(self):
  178. cids = self.channels['cids']
  179. if self.channels['event_cid']:
  180. cids.append(self.channels['event_cid'])
  181. return cids
  182. def create_channels(self):
  183. import ts3
  184. server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
  185. server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
  186. server.use(1)
  187. # Create the parent channel
  188. if not self.event_cid:
  189. # Find the LFG channel and place this one after
  190. response = server.send_command('channelfind', keys={'pattern': 'Looking for Group'})
  191. if response.is_successful:
  192. cid = response.data[0]['cid']
  193. response = server.send_command('channelcreate', keys={'channel_name':self.name.encode('utf-8'), 'channel_flag_semi_permanent':'1', 'channel_order':cid})
  194. if response.is_successful:
  195. self.channels['event_cid'] = response.data[0]['cid']
  196. # Create the subchannels
  197. if not self.cids:
  198. cids = []
  199. keys = {'channel_name':'Event Room #{}'.format(len(self.cids) + 1), 'channel_flag_semi_permanent':'1', 'cpid':self.event_cid.encode('utf-8')}
  200. response = server.send_command('channelcreate', keys=keys)
  201. if response.is_successful:
  202. parent_cid = response.data[0]['cid']
  203. cids.append(parent_cid)
  204. else:
  205. raise UserWarning("channelcreate failed")
  206. response = server.send_command('channelcreate', keys={'channel_name':'Radiant Team', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
  207. if response.is_successful:
  208. cids.append(response.data[0]['cid'])
  209. response = server.send_command('channelcreate', keys={'channel_name':'Dire Team', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
  210. if response.is_successful:
  211. cids.append(response.data[0]['cid'])
  212. response = server.send_command('channelcreate', keys={'channel_name':'Spectators', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
  213. if response.is_successful:
  214. cids.append(response.data[0]['cid'])
  215. self.channels['cids'] = cids
  216. db.session.commit()
  217. def remove_channels(self):
  218. import ts3
  219. server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
  220. server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
  221. server.use(1)
  222. response = server.send_command('channeldelete', keys={'cid':self.event_cid.encode('utf-8'), 'force':'1'})
  223. if response.is_successful:
  224. self.channels = {'event_cid': None, 'cids':[]}
  225. db.session.commit()
  226. @property
  227. def active(self):
  228. current_time = datetime.utcnow()
  229. return self.start_time < current_time and current_time < self.end_time
  230. @property
  231. def expired(self):
  232. current_time = datetime.utcnow()
  233. return self.end_time < current_time
  234. def add_participant(self, user):
  235. entry = self.participants.setdefault(user, {'start_time': datetime.utcnow() })
  236. entry['end_time'] = datetime.utcnow()
  237. if 'points' not in entry and (entry['end_time'] - entry['start_time']) > self.reward_threshold:
  238. user.points_from_events += self.points
  239. entry['points'] = self.points
  240. db.session.commit()
  241. @property
  242. def participants(self):
  243. return tuple(self.participants)
  244. def __repr__(self):
  245. return '<Event {}>'.format(self.id)