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.

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