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.

299 lines
11 KiB

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