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.

284 lines
11 KiB

10 years ago
10 years ago
  1. import simplejson as json
  2. from datetime import datetime
  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_connections = db.Column(MutableDict.as_mutable(Json))
  73. last_post_reward = db.Column(db.Integer)
  74. winrate_data = db.Column(MutableDict.as_mutable(Json))
  75. @classmethod
  76. def get_or_create(self, steam_id):
  77. return get_or_create_instance(db.session, User, steam_id=steam_id)
  78. @classmethod
  79. def get_streaming_users(self):
  80. twitch_streams = []
  81. hitbox_streams = []
  82. for user in User.query.all():
  83. if user.points_from_events + user.points_from_ts3 + user.points_from_forum < 5: continue
  84. if user.twitch:
  85. twitch_streams.append(user.twitch)
  86. if user.hitbox:
  87. hitbox_streams.append(user.hitbox)
  88. return {'twitch': twitch_streams, 'hitbox': hitbox_streams}
  89. def __init__(self, steam_id):
  90. self.steam_id = steam_id
  91. self.az_completions = 0
  92. self.ts3_connections = {'list':[]}
  93. self.ts3_rewardtime = datetime.utcnow()
  94. self.created = datetime.utcnow()
  95. self.last_seen = datetime.utcnow()
  96. self.bio_text = None
  97. self.points_from_events = 0
  98. self.points_from_ts3 = 0
  99. self.points_from_forum = 0
  100. self.admin = False
  101. self.public = True
  102. self.biglogo = True
  103. def update_connection(self, reward_threshold=30):
  104. now = datetime.utcnow()
  105. self.ts3_starttime = self.ts3_starttime or now
  106. self.ts3_endtime = now
  107. # Add general TS3 points here
  108. if self.ts3_endtime and self.ts3_rewardtime:
  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. else:
  115. self.ts3_rewardtime = datetime.utcnow()
  116. self.last_seen = datetime.utcnow()
  117. db.session.commit();
  118. def finalize_connection(self):
  119. self.ts3_connections['list'].append({'starttime': self.ts3_starttime, 'endtime': self.ts3_endtime})
  120. self.ts3_startime = None
  121. self.ts3_endtime = None
  122. db.session.commit();
  123. def update_forum_posts(self, reward_threshold=5):
  124. if self.forum_id:
  125. posts = board.Users.select().where(board.Users.id == int(self.forum_id))[0].posts
  126. if self.last_post_reward:
  127. num_points = (posts - self.last_post_reward) / reward_threshold
  128. if num_points > 0:
  129. self.points_from_forum += num_points
  130. self.last_post_reward += num_points * reward_threshold
  131. else:
  132. # Initialize if this is the first reward
  133. self.last_post_reward = posts
  134. db.session.commit()
  135. @property
  136. def is_active(self):
  137. return self.ts3_starttime and True or False
  138. def __repr__(self):
  139. return '<User {}>'.format(self.id)
  140. class TeamspeakData(db.Model):
  141. id = db.Column(db.Integer, primary_key=True)
  142. time = db.Column(db.DateTime())
  143. clients = db.Column(Json())
  144. def __init__(self, clientlist):
  145. self.time = datetime.utcnow()
  146. self.clients = clientlist
  147. class Event(db.Model):
  148. id = db.Column(db.Integer, primary_key=True)
  149. name = db.Column(db.String(200))
  150. desc = db.Column(db.String(4096))
  151. type = db.Column(db.String(20))
  152. start_time = db.Column(db.DateTime)
  153. end_time = db.Column(db.DateTime)
  154. points = db.Column(db.Integer)
  155. reward_threshold = db.Column(db.Integer)
  156. total_subchans = db.Column(db.Integer)
  157. channels = db.Column(MutableDict.as_mutable(Json))
  158. participants = db.Column(MutableDict.as_mutable(Json))
  159. def __init__(self, id):
  160. self.channels = {'event_cid':None, 'cids':[]}
  161. @classmethod
  162. def get_or_create(self, event_id):
  163. return get_or_create_instance(db.session, Event, id=event_id)
  164. @property
  165. def cids(self):
  166. return self.channels['cids']
  167. @property
  168. def event_cid(self):
  169. return self.channels['event_cid']
  170. @property
  171. def channel_ids(self):
  172. cids = self.channels['cids']
  173. if self.channels['event_cid']:
  174. cids.append(self.channels['event_cid'])
  175. return cids
  176. def create_channels(self):
  177. import ts3
  178. server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
  179. server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
  180. server.use(1)
  181. # Create the parent channel
  182. if not self.event_cid:
  183. # Find the LFG channel and place this one after
  184. response = server.send_command('channelfind', keys={'pattern': 'Looking for Group'})
  185. if response.is_successful:
  186. cid = response.data[0]['cid']
  187. response = server.send_command('channelcreate', keys={'channel_name':self.name.encode('utf-8'), 'channel_flag_semi_permanent':'1', 'channel_order':cid})
  188. if response.is_successful:
  189. self.channels['event_cid'] = response.data[0]['cid']
  190. # Create the subchannels
  191. if not self.cids:
  192. cids = []
  193. keys = {'channel_name':'Event Room #{}'.format(len(self.cids) + 1), 'channel_flag_semi_permanent':'1', 'cpid':self.event_cid.encode('utf-8')}
  194. response = server.send_command('channelcreate', keys=keys)
  195. if response.is_successful:
  196. parent_cid = response.data[0]['cid']
  197. cids.append(parent_cid)
  198. else:
  199. raise UserWarning("channelcreate failed")
  200. response = server.send_command('channelcreate', keys={'channel_name':'Radiant Team', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
  201. if response.is_successful:
  202. cids.append(response.data[0]['cid'])
  203. response = server.send_command('channelcreate', keys={'channel_name':'Dire Team', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
  204. if response.is_successful:
  205. cids.append(response.data[0]['cid'])
  206. response = server.send_command('channelcreate', keys={'channel_name':'Spectators', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
  207. if response.is_successful:
  208. cids.append(response.data[0]['cid'])
  209. self.channels['cids'] = cids
  210. db.session.commit()
  211. def remove_channels(self):
  212. import ts3
  213. server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
  214. server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
  215. server.use(1)
  216. response = server.send_command('channeldelete', keys={'cid':self.event_cid.encode('utf-8'), 'force':'1'})
  217. if response.is_successful:
  218. self.channels = {'event_cid': None, 'cids':[]}
  219. db.session.commit()
  220. @property
  221. def active(self):
  222. current_time = datetime.utcnow()
  223. return self.start_time < current_time and current_time < self.end_time
  224. @property
  225. def expired(self):
  226. current_time = datetime.utcnow()
  227. return self.end_time < curent_time
  228. def add_participant(self, user):
  229. entry = self.participants.setdefault(user, {'start_time': datetime.utcnow() })
  230. entry['end_time'] = datetime.utcnow()
  231. if 'points' not in entry and (entry['end_time'] - entry['start_time']) > self.reward_threshold:
  232. user.points_from_events += self.points
  233. entry['points'] = self.points
  234. db.session.commit()
  235. @property
  236. def participants(self):
  237. return tuple(self.participants)
  238. def __repr__(self):
  239. return '<Event {}>'.format(self.id)