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.

309 lines
12 KiB

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