Update before moving GIT heirarchy
This commit is contained in:
		
							parent
							
								
									23e04edafd
								
							
						
					
					
						commit
						3160967fa8
					
				
							
								
								
									
										220
									
								
								__init__.py
									
									
									
									
									
								
							
							
						
						
									
										220
									
								
								__init__.py
									
									
									
									
									
								
							@ -9,222 +9,4 @@ db = SQLAlchemy(app)
 | 
				
			|||||||
oid = OpenID(app)
 | 
					oid = OpenID(app)
 | 
				
			||||||
cache = Cache(app, config={'CACHE_TYPE': app.config['CACHE_TYPE']})
 | 
					cache = Cache(app, config={'CACHE_TYPE': app.config['CACHE_TYPE']})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from app import views
 | 
					from app import views, models
 | 
				
			||||||
 | 
					 | 
				
			||||||
'''
 | 
					 | 
				
			||||||
from flask import Flask, render_template
 | 
					 | 
				
			||||||
from flask.ext.mongoengine import MongoEngine
 | 
					 | 
				
			||||||
from flask.ext.openid import OpenID
 | 
					 | 
				
			||||||
from flask.ext.cache import Cache
 | 
					 | 
				
			||||||
import utils
 | 
					 | 
				
			||||||
import ts3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
app = Flask(__name__)
 | 
					 | 
				
			||||||
app.config.from_object('config')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#Setup mongo database
 | 
					 | 
				
			||||||
db = MongoEngine(app)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#Setup OpenID and Caching
 | 
					 | 
				
			||||||
oid = OpenID(app)
 | 
					 | 
				
			||||||
cache = Cache(app, config={'CACHE_TYPE': app.config['CACHE_TYPE']})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from app import views
 | 
					 | 
				
			||||||
@app.route('/')
 | 
					 | 
				
			||||||
def inx():
 | 
					 | 
				
			||||||
	return render_template('main.html')
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
##### INTO UTILS LATER #####
 | 
					 | 
				
			||||||
RADIANT_TEAM = 2
 | 
					 | 
				
			||||||
DIRE_TEAM = 3
 | 
					 | 
				
			||||||
RADIANT_COLOR = 'b'
 | 
					 | 
				
			||||||
DIRE_COLOR = 'r'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def get_hero_data():
 | 
					 | 
				
			||||||
	xhr = urllib2.build_opener().open(urllib2.Request("https://api.steampowered.com/IEconDOTA2_570/GETHeroes/v0001/?key="+DOTA2_API_KEY+"&language=en_us"))
 | 
					 | 
				
			||||||
	data = json.load(xhr)
 | 
					 | 
				
			||||||
	return data
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
@app.context_processor
 | 
					 | 
				
			||||||
def utility_processor():
 | 
					 | 
				
			||||||
	@cache.memoize(60*5)
 | 
					 | 
				
			||||||
	def ts3_viewer():
 | 
					 | 
				
			||||||
		try:
 | 
					 | 
				
			||||||
			server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
 | 
					 | 
				
			||||||
			server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
 | 
					 | 
				
			||||||
			server.use(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			serverinfo = server.send_command('serverinfo').data
 | 
					 | 
				
			||||||
			channellist = server.send_command('channellist', opts=("limits", "flags", "voice", "icon")).data
 | 
					 | 
				
			||||||
			clientlist = server.send_command('clientlist', opts=("away", "voice", "info", "icon", "groups", "country")).data
 | 
					 | 
				
			||||||
			servergrouplist = server.send_command('servergrouplist').data
 | 
					 | 
				
			||||||
			channelgrouplist = server.send_command('channelgrouplist').data
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			soup = BeautifulSoup()
 | 
					 | 
				
			||||||
			div_tag = soup.new_tag('div')
 | 
					 | 
				
			||||||
			div_tag['class'] ='devmx-webviewer'
 | 
					 | 
				
			||||||
			soup.append(div_tag)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			def construct_channels(parent_tag, cid):
 | 
					 | 
				
			||||||
				num_clients = 0
 | 
					 | 
				
			||||||
				for channel in channellist:
 | 
					 | 
				
			||||||
					if int(channel['pid']) == int(cid):
 | 
					 | 
				
			||||||
						# Construct the channel
 | 
					 | 
				
			||||||
						channel_tag = soup.new_tag('div')
 | 
					 | 
				
			||||||
						channel_tag['class'] = 'tswv-channel'
 | 
					 | 
				
			||||||
						# Channel image
 | 
					 | 
				
			||||||
						image_tag = soup.new_tag('span')
 | 
					 | 
				
			||||||
						image_tag['class'] = 'tswv-image tswv-image-right'
 | 
					 | 
				
			||||||
						if int(channel['channel_flag_password']) == 1:
 | 
					 | 
				
			||||||
							image_tag['class'] += ' tswv-channel-password-right'
 | 
					 | 
				
			||||||
						if int(channel['channel_flag_default']) == 1:
 | 
					 | 
				
			||||||
							image_tag['class'] += ' tswv-channel-home'
 | 
					 | 
				
			||||||
						if int(channel['channel_needed_talk_power']) > 0:
 | 
					 | 
				
			||||||
							image_tag['class'] += ' tswv-channel-moderated'
 | 
					 | 
				
			||||||
						if int(channel['channel_icon_id']) != 0:
 | 
					 | 
				
			||||||
							raise NotImplementedError
 | 
					 | 
				
			||||||
						image_tag.append(' ')
 | 
					 | 
				
			||||||
						channel_tag.append(image_tag)
 | 
					 | 
				
			||||||
						# Status image
 | 
					 | 
				
			||||||
						status_tag = soup.new_tag('span')
 | 
					 | 
				
			||||||
						status_tag['class'] = 'tswv-image'
 | 
					 | 
				
			||||||
						if int(channel['channel_flag_password']) == 1:
 | 
					 | 
				
			||||||
							status_tag['class'] += ' tswv-channel-password'
 | 
					 | 
				
			||||||
						elif int(channel['total_clients']) == int(channel['channel_maxclients']):
 | 
					 | 
				
			||||||
							status_tag['class'] += ' tswv-channel-full'
 | 
					 | 
				
			||||||
						else:
 | 
					 | 
				
			||||||
							status_tag['class'] += ' tswv-channel-normal'
 | 
					 | 
				
			||||||
						status_tag.append(' ')
 | 
					 | 
				
			||||||
						channel_tag.append(status_tag)
 | 
					 | 
				
			||||||
						# Label
 | 
					 | 
				
			||||||
						label_tag = soup.new_tag('span')
 | 
					 | 
				
			||||||
						label_tag['class'] = 'tswv-label'
 | 
					 | 
				
			||||||
						label_tag.append(channel['channel_name'])
 | 
					 | 
				
			||||||
						channel_tag.append(label_tag)
 | 
					 | 
				
			||||||
						# Clients
 | 
					 | 
				
			||||||
						channel_tag, channel_clients = construct_clients(channel_tag, channel['cid'])
 | 
					 | 
				
			||||||
						# Recurse through sub-channels, collecting total number of clients as we go
 | 
					 | 
				
			||||||
						channel_tag, sub_clients = construct_channels(channel_tag, channel['cid'])
 | 
					 | 
				
			||||||
						channel_clients += sub_clients
 | 
					 | 
				
			||||||
						# Only show non-empty channels
 | 
					 | 
				
			||||||
						if channel_clients > 0:
 | 
					 | 
				
			||||||
							parent_tag.append(channel_tag)
 | 
					 | 
				
			||||||
							num_clients += channel_clients
 | 
					 | 
				
			||||||
				return parent_tag, num_clients
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			def construct_clients(parent_tag, cid):
 | 
					 | 
				
			||||||
				num_clients = 0
 | 
					 | 
				
			||||||
				for client in clientlist:
 | 
					 | 
				
			||||||
					if int(client['cid']) == int(cid):
 | 
					 | 
				
			||||||
						# Skip ServerQuery clients
 | 
					 | 
				
			||||||
						if int(client['client_type']) == 1: continue
 | 
					 | 
				
			||||||
						num_clients += 1
 | 
					 | 
				
			||||||
						client_tag = soup.new_tag('div')
 | 
					 | 
				
			||||||
						client_tag['class'] = 'tswv-client'
 | 
					 | 
				
			||||||
						# Status image
 | 
					 | 
				
			||||||
						status_tag = soup.new_tag('span')
 | 
					 | 
				
			||||||
						status_tag['class'] = 'tswv-image'
 | 
					 | 
				
			||||||
						if int(client['client_type']) == 1:
 | 
					 | 
				
			||||||
							status_tag['class'] += ' tswv-client-query'
 | 
					 | 
				
			||||||
						elif int(client['client_away']) == 1:
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-away"
 | 
					 | 
				
			||||||
						elif int(client['client_input_muted']) == 1:
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-input-muted"
 | 
					 | 
				
			||||||
						elif int(client['client_output_muted']) == 1:
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-output-muted"
 | 
					 | 
				
			||||||
						elif int(client['client_input_hardware']) == 0:
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-input-muted-hardware"
 | 
					 | 
				
			||||||
						elif int(client['client_output_hardware']) == 0:
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-output-muted-hardware"
 | 
					 | 
				
			||||||
						elif (int(client['client_flag_talking']) == 1) and (int(client['client_is_channel_commander']) == 1):
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-channel-commander-talking"
 | 
					 | 
				
			||||||
						elif int(client['client_is_channel_commander']) == 1:
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-channel-commander"
 | 
					 | 
				
			||||||
						elif int(client['client_flag_talking']) == 1:	
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-talking"
 | 
					 | 
				
			||||||
						else:
 | 
					 | 
				
			||||||
							status_tag['class'] += " tswv-client-normal"
 | 
					 | 
				
			||||||
						status_tag.append(' ')
 | 
					 | 
				
			||||||
						client_tag.append(status_tag)
 | 
					 | 
				
			||||||
						# Country image
 | 
					 | 
				
			||||||
						country_tag = soup.new_tag('span')
 | 
					 | 
				
			||||||
						country_tag['class'] = 'tswv-image tswv-image-right'
 | 
					 | 
				
			||||||
						country_tag['title'] = ' '.join([word.capitalize() for word in utils.ISO3166_MAPPING[client['client_country']].split(' ')])
 | 
					 | 
				
			||||||
						country_tag['style'] = 'background: url("%s") center center no-repeat;' % url_for('static', filename='img/ts3_viewer/countries/%s.png' % client['client_country'].lower())
 | 
					 | 
				
			||||||
						country_tag.append(' ')
 | 
					 | 
				
			||||||
						client_tag.append(country_tag)
 | 
					 | 
				
			||||||
						# Server group images
 | 
					 | 
				
			||||||
						sgids = [int(sg) for sg in client['client_servergroups'].split(',')]
 | 
					 | 
				
			||||||
						servergroups = [servergroup for servergroup in servergrouplist if int(servergroup['sgid']) in sgids]
 | 
					 | 
				
			||||||
						servergroups.sort(key=operator.itemgetter('sortid'))
 | 
					 | 
				
			||||||
						for servergroup in servergroups:
 | 
					 | 
				
			||||||
							if not servergroup['iconid']: continue
 | 
					 | 
				
			||||||
							img_fname = 'img/ts3_viewer/%s.png' % servergroup['iconid']
 | 
					 | 
				
			||||||
							if not os.path.exists(os.path.join(app.static_folder, img_fname)):
 | 
					 | 
				
			||||||
								continue
 | 
					 | 
				
			||||||
							image_tag = soup.new_tag('span')
 | 
					 | 
				
			||||||
							image_tag['class'] = 'tswv-image tswv-image-right'
 | 
					 | 
				
			||||||
							image_tag['title'] = servergroup['name']
 | 
					 | 
				
			||||||
							image_tag['style'] = 'background-image: url("%s")' % url_for('static', filename=img_fname)
 | 
					 | 
				
			||||||
							image_tag.append(' ')
 | 
					 | 
				
			||||||
							client_tag.append(image_tag)
 | 
					 | 
				
			||||||
						# Check if client is in a moderated channel
 | 
					 | 
				
			||||||
						channel = [channel for channel in channellist if int(channel['cid']) == int(client['cid'])][0]
 | 
					 | 
				
			||||||
						if int(channel['channel_needed_talk_power']) > 0:
 | 
					 | 
				
			||||||
							status_tag = soup.new_tag('span')
 | 
					 | 
				
			||||||
							status_tag['class'] = 'tswv-image tswv-image-right'
 | 
					 | 
				
			||||||
							if int(client['client_is_talker']) == 0:
 | 
					 | 
				
			||||||
								status_tag['class'] += ' tswv-client-input-muted'
 | 
					 | 
				
			||||||
							else:
 | 
					 | 
				
			||||||
								status_tag['class'] += ' tswv-client-talkpower-granted'
 | 
					 | 
				
			||||||
							status_tag.append(' ')
 | 
					 | 
				
			||||||
							client_tag.append(status_tag)
 | 
					 | 
				
			||||||
						# Label
 | 
					 | 
				
			||||||
						label_tag = soup.new_tag('span')
 | 
					 | 
				
			||||||
						label_tag['class'] = 'tswv-label'
 | 
					 | 
				
			||||||
						label_tag.append(client['client_nickname'])
 | 
					 | 
				
			||||||
						client_tag.append(label_tag)
 | 
					 | 
				
			||||||
						parent_tag.append(client_tag)
 | 
					 | 
				
			||||||
				return parent_tag, num_clients
 | 
					 | 
				
			||||||
			div_tag, num_clients = construct_channels(div_tag, 0)
 | 
					 | 
				
			||||||
			return soup.prettify()
 | 
					 | 
				
			||||||
		except Exception as inst:
 | 
					 | 
				
			||||||
			return "error: %s" % inst
 | 
					 | 
				
			||||||
	def shorten_text(text, num_words=10):
 | 
					 | 
				
			||||||
		text = utils.fix_bad_unicode(text)
 | 
					 | 
				
			||||||
		space_iter = re.finditer('\s+', text)
 | 
					 | 
				
			||||||
		output = u''
 | 
					 | 
				
			||||||
		while num_words > 0:
 | 
					 | 
				
			||||||
			match = space_iter.next()
 | 
					 | 
				
			||||||
			if not match: break
 | 
					 | 
				
			||||||
			output = text[:match.end()]
 | 
					 | 
				
			||||||
			num_words -= 1
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			output += '...'
 | 
					 | 
				
			||||||
		return output
 | 
					 | 
				
			||||||
	def num_unique_clients(teamspeak_data):
 | 
					 | 
				
			||||||
		unique_clients = set()
 | 
					 | 
				
			||||||
		for data in teamspeak_data:
 | 
					 | 
				
			||||||
			unique_clients.update(data.clients)
 | 
					 | 
				
			||||||
		return len(unique_clients)
 | 
					 | 
				
			||||||
	def num_unique_clients_by_country(teamspeak_data):
 | 
					 | 
				
			||||||
		unique_clients = {}
 | 
					 | 
				
			||||||
		for data in teamspeak_data:
 | 
					 | 
				
			||||||
			for client_id, client_data in data.clients.iteritems():
 | 
					 | 
				
			||||||
				unique_clients[client_id] = (client_data['country'] or 'Unknown').lower()
 | 
					 | 
				
			||||||
		country = {}
 | 
					 | 
				
			||||||
		for client_id, country_code in unique_clients.iteritems():
 | 
					 | 
				
			||||||
			country[country_code] = country.get(country_code, 0) + 1
 | 
					 | 
				
			||||||
		return country
 | 
					 | 
				
			||||||
	def country_abbreviation_mapping():
 | 
					 | 
				
			||||||
		mapping = {}
 | 
					 | 
				
			||||||
		for key, name in utils.ISO3166_MAPPING.iteritems():
 | 
					 | 
				
			||||||
			mapping[key.lower()] = ' '.join([word.capitalize() for word in name.split(' ')])
 | 
					 | 
				
			||||||
		return mapping
 | 
					 | 
				
			||||||
	return dict(timestamp_to_js_date=utils.timestamp_to_js_date, ts3_viewer=ts3_viewer, shorten_text=shorten_text, getTeamspeakWindow=doob.getTeamspeakWindow,
 | 
					 | 
				
			||||||
			num_unique_clients=num_unique_clients,
 | 
					 | 
				
			||||||
			num_unique_clients_by_country=num_unique_clients_by_country,
 | 
					 | 
				
			||||||
			country_abbreviation_mapping=country_abbreviation_mapping)
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			'''
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										24
									
								
								board.py
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								board.py
									
									
									
									
									
								
							@ -1,17 +1,31 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
from time import strftime, gmtime
 | 
					from time import strftime, gmtime
 | 
				
			||||||
 | 
					from hashlib import sha256
 | 
				
			||||||
from peewee import *
 | 
					from peewee import *
 | 
				
			||||||
from app import app, cache
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
db = MySQLDatabase(app.config['FORUM_NAME'], **{'passwd': app.config['FORUM_PASSWORD'],
 | 
					from app import app, cache, db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					board_db = MySQLDatabase(app.config['FORUM_NAME'], **{'passwd': app.config['FORUM_PASSWORD'],
 | 
				
			||||||
					'host': app.config['FORUM_HOST'], 'user': app.config['FORUM_USERNAME']})
 | 
										'host': app.config['FORUM_HOST'], 'user': app.config['FORUM_USERNAME']})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def registerUserForumId(user, username, password):
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        u = Users.filter(name=username).get()
 | 
				
			||||||
 | 
					        hashpass = sha256(password+app.config['FORUM_SALT']+u.pss).hexdigest()
 | 
				
			||||||
 | 
					        if hashpass == u.password:
 | 
				
			||||||
 | 
					            user.forum_id = u.id
 | 
				
			||||||
 | 
					            db.session.commit()
 | 
				
			||||||
 | 
					            return {"forum_name":u.name, "forum_id":u.id}
 | 
				
			||||||
 | 
					    except DoesNotExist:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@cache.memoize(60*5)
 | 
					@cache.memoize(60*5)
 | 
				
			||||||
def latest_news(num=3):
 | 
					def latest_news(num=3):
 | 
				
			||||||
	latest_news = []
 | 
						latest_news = []
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
		db.connect()
 | 
							board_db.connect()
 | 
				
			||||||
		news_forum = Forums.get(fn.Lower(Forums.title) % '%news%')
 | 
							news_forum = Forums.get(fn.Lower(Forums.title) % '%news%')
 | 
				
			||||||
		for thread in Threads.select().where(
 | 
							for thread in Threads.select().where(
 | 
				
			||||||
			Threads.forum == news_forum.id).order_by(Threads.date.desc()).limit(num):
 | 
								Threads.forum == news_forum.id).order_by(Threads.date.desc()).limit(num):
 | 
				
			||||||
@ -32,7 +46,7 @@ def latest_news(num=3):
 | 
				
			|||||||
	except Exception as e:
 | 
						except Exception as e:
 | 
				
			||||||
		latest_news.append({'title':'Error with forum db', 'text':e, 'url':''})
 | 
							latest_news.append({'title':'Error with forum db', 'text':e, 'url':''})
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
		db.close()
 | 
							board_db.close()
 | 
				
			||||||
	return latest_news
 | 
						return latest_news
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
class UnknownFieldType(object):
 | 
					class UnknownFieldType(object):
 | 
				
			||||||
@ -40,7 +54,7 @@ class UnknownFieldType(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class BaseModel(Model):
 | 
					class BaseModel(Model):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        database = db
 | 
					        database = board_db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Badges(BaseModel):
 | 
					class Badges(BaseModel):
 | 
				
			||||||
    color = IntegerField()
 | 
					    color = IntegerField()
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								forms.py
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								forms.py
									
									
									
									
									
								
							@ -1,7 +1,23 @@
 | 
				
			|||||||
from flask.ext.wtf import Form
 | 
					from flask_wtf import Form
 | 
				
			||||||
from wtforms import TextField, BooleanField, TextAreaField
 | 
					from wtforms import TextField, BooleanField, TextAreaField, PasswordField, SelectField, IntegerField, DateTimeField, validators
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SettingsForm(Form):
 | 
					class SettingsForm(Form):
 | 
				
			||||||
    public = BooleanField('public', default=True)
 | 
					    public = BooleanField('public', default=True)
 | 
				
			||||||
 | 
					    logo = BooleanField('biglogo', default=True)
 | 
				
			||||||
    twitch = TextField('twitch')
 | 
					    twitch = TextField('twitch')
 | 
				
			||||||
    bio_text = TextAreaField('bio_text')
 | 
					    bio_text = TextAreaField('bio_text')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EnableStatsForm(Form):
 | 
				
			||||||
 | 
					    teamspeak_id = TextField('teamspeak_id')
 | 
				
			||||||
 | 
					    forum_username = TextField('forum_username')
 | 
				
			||||||
 | 
					    forum_password = PasswordField('forum_password')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EventForm(Form):
 | 
				
			||||||
 | 
					    name = TextField('name', [validators.Required()])
 | 
				
			||||||
 | 
					    desc = TextAreaField('desc', [validators.Required()])
 | 
				
			||||||
 | 
					    type = SelectField(u'Event Type', choices=[('coaching', 'Coaching'), ('inhouse', 'In-House'), ('tournament', 'Tournament'), ('other', 'Other')])
 | 
				
			||||||
 | 
					    start_time = DateTimeField('start_time', format='%d.%m.%Y %H:%M')
 | 
				
			||||||
 | 
					    end_time = DateTimeField('end_time', format='%d.%m.%Y %H:%M')
 | 
				
			||||||
 | 
					    points = IntegerField('points', [validators.Required()])
 | 
				
			||||||
 | 
					    reward_threshold = IntegerField('reward_threshold')
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										221
									
								
								models.py
									
									
									
									
									
								
							
							
						
						
									
										221
									
								
								models.py
									
									
									
									
									
								
							@ -1,11 +1,23 @@
 | 
				
			|||||||
import simplejson as json
 | 
					import simplejson as json
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
from random import choice
 | 
					from random import choice
 | 
				
			||||||
from flask.ext.sqlalchemy import SQLAlchemy
 | 
					from flask.ext.sqlalchemy import SQLAlchemy
 | 
				
			||||||
from sqlalchemy.ext.mutable import Mutable
 | 
					from sqlalchemy.ext.mutable import Mutable
 | 
				
			||||||
from time import time
 | 
					
 | 
				
			||||||
from app import db
 | 
					import board
 | 
				
			||||||
 | 
					from app import db, app
 | 
				
			||||||
from utils import parse_valve_heropedia, complete_hero_data
 | 
					from utils import parse_valve_heropedia, complete_hero_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Model independant get_or_create
 | 
				
			||||||
 | 
					def get_or_create_instance(session, model, **kwargs):
 | 
				
			||||||
 | 
					    instance = session.query(model).filter_by(**kwargs).first()
 | 
				
			||||||
 | 
					    if instance:
 | 
				
			||||||
 | 
					        return instance
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        instance = model(**kwargs)
 | 
				
			||||||
 | 
					        session.add(instance)
 | 
				
			||||||
 | 
					        return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Get a little of that Mongoness back
 | 
					# Get a little of that Mongoness back
 | 
				
			||||||
class Json(db.TypeDecorator):
 | 
					class Json(db.TypeDecorator):
 | 
				
			||||||
    impl = db.Text
 | 
					    impl = db.Text
 | 
				
			||||||
@ -20,7 +32,7 @@ class Json(db.TypeDecorator):
 | 
				
			|||||||
            value = json.loads(value)
 | 
					            value = json.loads(value)
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mongoness factor - phase 2
 | 
				
			||||||
class MutableDict(Mutable, dict):
 | 
					class MutableDict(Mutable, dict):
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def coerce(cls, key, value):
 | 
					    def coerce(cls, key, value):
 | 
				
			||||||
@ -46,27 +58,51 @@ class MutableDict(Mutable, dict):
 | 
				
			|||||||
        self.update(self)
 | 
					        self.update(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class User(db.Model):
 | 
					class User(db.Model):
 | 
				
			||||||
	id = db.Column(db.Integer, primary_key=True)
 | 
						id = db.Column(db.Integer, primary_key=True)
 | 
				
			||||||
	steam_id = db.Column(db.String(40), unique=True)
 | 
						steam_id = db.Column(db.String(40), unique=True)
 | 
				
			||||||
 | 
					        forum_id = db.Column(db.Integer)
 | 
				
			||||||
 | 
					        teamspeak_id = db.Column(db.String(200), unique=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nickname = db.Column(db.String(80))
 | 
						nickname = db.Column(db.String(80))
 | 
				
			||||||
	avatar = db.Column(db.String(255))
 | 
						avatar = db.Column(db.String(255))
 | 
				
			||||||
        random_heroes = db.Column(MutableDict.as_mutable(Json))
 | 
					        admin = db.Column(db.Boolean)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bio_text = db.Column(db.String(4096))
 | 
					        bio_text = db.Column(db.String(4096))
 | 
				
			||||||
 | 
					        created = db.Column(db.DateTime)
 | 
				
			||||||
        last_seen = db.Column(db.DateTime)
 | 
					        last_seen = db.Column(db.DateTime)
 | 
				
			||||||
        twitch = db.Column(db.String(60))
 | 
					        twitch = db.Column(db.String(60))
 | 
				
			||||||
	
 | 
					        random_heroes = db.Column(MutableDict.as_mutable(Json))
 | 
				
			||||||
	@staticmethod
 | 
					
 | 
				
			||||||
	def get_or_create(steam_id):
 | 
					        public = db.Column(db.Boolean)
 | 
				
			||||||
            rv = User.query.filter_by(steam_id=steam_id).first()
 | 
					        logo = db.Column(db.Boolean)
 | 
				
			||||||
            if rv is None:
 | 
					
 | 
				
			||||||
                rv = User()
 | 
					        points_from_events = db.Column(db.Integer)
 | 
				
			||||||
                rv.steam_id = steam_id
 | 
					        points_from_ts3 = db.Column(db.Integer)
 | 
				
			||||||
                rv.random_heroes = {'current':None, 'completed':[]}
 | 
					        points_from_forum = db.Column(db.Integer)
 | 
				
			||||||
                bio_text = ''
 | 
					        ts3_starttime = db.Column(db.DateTime)
 | 
				
			||||||
                db.session.add(rv)
 | 
					        ts3_endtime = db.Column(db.DateTime)
 | 
				
			||||||
            return rv
 | 
					        ts3_rewardtime = db.Column(db.DateTime)
 | 
				
			||||||
 | 
					        ts3_connections = db.Column(MutableDict.as_mutable(Json))
 | 
				
			||||||
 | 
					        last_post_reward = db.Column(db.Integer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @classmethod
 | 
				
			||||||
 | 
					        def get_or_create(self, steam_id):
 | 
				
			||||||
 | 
					            return get_or_create_instance(db.session, User, steam_id=steam_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def __init__(self, steam_id):
 | 
				
			||||||
 | 
					            self.steam_id = steam_id
 | 
				
			||||||
 | 
					            self.random_heroes = {'current':None, 'completed':[]}
 | 
				
			||||||
 | 
					            self.created = datetime.utcnow()
 | 
				
			||||||
 | 
					            self.last_seen = datetime.utcnow()
 | 
				
			||||||
 | 
					            self.bio_text = None 
 | 
				
			||||||
 | 
					            self.points_from_events = 0
 | 
				
			||||||
 | 
					            self.points_from_ts3 = 0
 | 
				
			||||||
 | 
					            self.points_from_forum = 0
 | 
				
			||||||
 | 
					            self.admin = False
 | 
				
			||||||
 | 
					            self.public = True
 | 
				
			||||||
 | 
					            self.biglogo = True
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        @property
 | 
					        @property
 | 
				
			||||||
        def random_hero(self):
 | 
					        def random_hero(self):
 | 
				
			||||||
@ -103,14 +139,161 @@ class User(db.Model):
 | 
				
			|||||||
            db.session.commit()
 | 
					            db.session.commit()
 | 
				
			||||||
            return self.random_hero
 | 
					            return self.random_hero
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def update_connection(self, reward_threshold=30):
 | 
				
			||||||
 | 
					            now = datetime.utcnow()
 | 
				
			||||||
 | 
					            self.ts3_starttime = self.ts3_starttime or now
 | 
				
			||||||
 | 
					            self.ts3_endtime = now
 | 
				
			||||||
 | 
					            # Add general TS3 points here
 | 
				
			||||||
 | 
					            if self.ts3_endtime and self.ts3_rewardtime:
 | 
				
			||||||
 | 
					                duration = (self.ts3_endtime - self.ts3_rewardtime) / 60.0
 | 
				
			||||||
 | 
					                if duration > reward_threshold:
 | 
				
			||||||
 | 
					                    self.ts3_rewardtime = datetime.utcnow()
 | 
				
			||||||
 | 
					                    self.points_from_ts3 += 1
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    self.ts3_rewardtime = datetime.utcnow()
 | 
				
			||||||
 | 
					            self.last_seen = datetime.utcnow()
 | 
				
			||||||
 | 
					            print self.ts3_starttime, self.ts3_endtime, self.ts3_rewardtime
 | 
				
			||||||
 | 
					            db.session.commit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def finalize_connection(self):
 | 
				
			||||||
 | 
					            self.ts3_connections.append({'starttime': self.ts3_starttime, 'endtime': self.ts3_endtime})
 | 
				
			||||||
 | 
					            self.ts3_startime = None
 | 
				
			||||||
 | 
					            self.ts3_endtime = None
 | 
				
			||||||
 | 
					            db.session.commit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def update_forum_posts(self, reward_threshold=5):
 | 
				
			||||||
 | 
					            if self.forum_id:
 | 
				
			||||||
 | 
					                posts = board.Users.select().where(board.Users.id == int(self.forum_id))[0].posts
 | 
				
			||||||
 | 
					                if self.last_post_reward:
 | 
				
			||||||
 | 
					                    num_points = (posts - self.last_post_reward) / reward_threshold
 | 
				
			||||||
 | 
					                    if num_points > 0:
 | 
				
			||||||
 | 
					                        self.points_from_forum += num_points
 | 
				
			||||||
 | 
					                        self.last_post_reward += num_points * reward_threshold
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    # Initialize if this is the first reward
 | 
				
			||||||
 | 
					                    self.last_post_reward = posts
 | 
				
			||||||
 | 
					                db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @property
 | 
				
			||||||
 | 
					        def is_active(self):
 | 
				
			||||||
 | 
					            return self.ts3_starttime and True or False 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __repr__(self):
 | 
						def __repr__(self):
 | 
				
			||||||
            return '<User {}>'.format(self.nickname)
 | 
					            return '<User {}>'.format(self.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TeamspeakData(db.Model):
 | 
					class TeamspeakData(db.Model):
 | 
				
			||||||
        id = db.Column(db.Integer, primary_key=True)
 | 
					        id = db.Column(db.Integer, primary_key=True)
 | 
				
			||||||
        time = db.Column(db.Float())
 | 
					        time = db.Column(db.DateTime())
 | 
				
			||||||
        clients = db.Column(Json())
 | 
					        clients = db.Column(Json())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def __init__(self, clientlist):
 | 
					        def __init__(self, clientlist):
 | 
				
			||||||
            self.time = time()
 | 
					            self.time = datetime.utcnow() 
 | 
				
			||||||
            self.clients = clientlist 
 | 
					            self.clients = clientlist 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Event(db.Model):
 | 
				
			||||||
 | 
					        id = db.Column(db.Integer, primary_key=True)
 | 
				
			||||||
 | 
					        name = db.Column(db.String(200))
 | 
				
			||||||
 | 
					        desc = db.Column(db.String(4096))
 | 
				
			||||||
 | 
					        type = db.Column(db.String(20))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        start_time = db.Column(db.DateTime)
 | 
				
			||||||
 | 
					        end_time = db.Column(db.DateTime)
 | 
				
			||||||
 | 
					        points = db.Column(db.Integer)
 | 
				
			||||||
 | 
					        reward_threshold = db.Column(db.Integer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        total_subchans = db.Column(db.Integer)
 | 
				
			||||||
 | 
					        channels = db.Column(MutableDict.as_mutable(Json))
 | 
				
			||||||
 | 
					        participants = db.Column(MutableDict.as_mutable(Json))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def __init__(self, id):
 | 
				
			||||||
 | 
					            self.channels = {'event_cid':None, 'cids':[]}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @classmethod
 | 
				
			||||||
 | 
					        def get_or_create(self, event_id):
 | 
				
			||||||
 | 
					            return get_or_create_instance(db.session, Event, id=event_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @property
 | 
				
			||||||
 | 
					        def cids(self):
 | 
				
			||||||
 | 
					            return self.channels['cids']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @property
 | 
				
			||||||
 | 
					        def event_cid(self):
 | 
				
			||||||
 | 
					            return self.channels['event_cid']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @property
 | 
				
			||||||
 | 
					        def channel_ids(self):
 | 
				
			||||||
 | 
					            cids = self.channels['cids']
 | 
				
			||||||
 | 
					            if self.channels['event_cid']:
 | 
				
			||||||
 | 
					                cids.append(self.channels['event_cid'])
 | 
				
			||||||
 | 
					            return cids
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def create_channels(self):
 | 
				
			||||||
 | 
					            import ts3
 | 
				
			||||||
 | 
					            server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
 | 
				
			||||||
 | 
					            server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
 | 
				
			||||||
 | 
					            server.use(1)
 | 
				
			||||||
 | 
					            # Create the parent channel
 | 
				
			||||||
 | 
					            if not self.event_cid:
 | 
				
			||||||
 | 
					                # Find the LFG channel and place this one after
 | 
				
			||||||
 | 
					                response = server.send_command('channelfind', keys={'pattern': 'Looking for Group'})
 | 
				
			||||||
 | 
					                if response.is_successful:
 | 
				
			||||||
 | 
					                    cid = response.data[0]['cid']
 | 
				
			||||||
 | 
					                response = server.send_command('channelcreate', keys={'channel_name':self.name.encode('utf-8'), 'channel_flag_semi_permanent':'1', 'channel_order':cid})
 | 
				
			||||||
 | 
					                if response.is_successful:
 | 
				
			||||||
 | 
					                    self.channels['event_cid'] = response.data[0]['cid']
 | 
				
			||||||
 | 
					            # Create the subchannels
 | 
				
			||||||
 | 
					            if not self.cids:
 | 
				
			||||||
 | 
					                cids = []
 | 
				
			||||||
 | 
					                keys = {'channel_name':'Event Room #{}'.format(len(self.cids) + 1), 'channel_flag_semi_permanent':'1', 'cpid':self.event_cid.encode('utf-8')}
 | 
				
			||||||
 | 
					                response = server.send_command('channelcreate', keys=keys)
 | 
				
			||||||
 | 
					                if response.is_successful:
 | 
				
			||||||
 | 
					                    parent_cid = response.data[0]['cid']
 | 
				
			||||||
 | 
					                    cids.append(parent_cid)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    raise UserWarning("channelcreate failed")
 | 
				
			||||||
 | 
					                response = server.send_command('channelcreate', keys={'channel_name':'Radiant Team', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
 | 
				
			||||||
 | 
					                if response.is_successful:
 | 
				
			||||||
 | 
					                    cids.append(response.data[0]['cid'])
 | 
				
			||||||
 | 
					                response = server.send_command('channelcreate', keys={'channel_name':'Dire Team', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
 | 
				
			||||||
 | 
					                if response.is_successful:
 | 
				
			||||||
 | 
					                    cids.append(response.data[0]['cid'])
 | 
				
			||||||
 | 
					                response = server.send_command('channelcreate', keys={'channel_name':'Spectators', 'channel_flag_semi_permanent':'1', 'cpid':parent_cid})
 | 
				
			||||||
 | 
					                if response.is_successful:
 | 
				
			||||||
 | 
					                    cids.append(response.data[0]['cid'])
 | 
				
			||||||
 | 
					                self.channels['cids'] = cids
 | 
				
			||||||
 | 
					            db.session.commit()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        def remove_channels(self):
 | 
				
			||||||
 | 
					            import ts3
 | 
				
			||||||
 | 
					            server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
 | 
				
			||||||
 | 
					            server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
 | 
				
			||||||
 | 
					            server.use(1)
 | 
				
			||||||
 | 
					            response = server.send_command('channeldelete', keys={'cid':self.event_cid.encode('utf-8'), 'force':'1'})
 | 
				
			||||||
 | 
					            if response.is_successful:
 | 
				
			||||||
 | 
					                self.channels = {'event_cid': None, 'cids':[]}
 | 
				
			||||||
 | 
					                db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @property
 | 
				
			||||||
 | 
					        def active(self):
 | 
				
			||||||
 | 
					            current_time = datetime.utcnow()
 | 
				
			||||||
 | 
					            return self.start_time < current_time and current_time < self.end_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @property
 | 
				
			||||||
 | 
					        def expired(self):
 | 
				
			||||||
 | 
					            current_time = datetime.utcnow()
 | 
				
			||||||
 | 
					            return self.end_time < curent_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def add_participant(self, user):
 | 
				
			||||||
 | 
					            entry = self.participants.setdefault(user, {'start_time': datetime.utcnow() })
 | 
				
			||||||
 | 
					            entry['end_time'] = datetime.utcnow()
 | 
				
			||||||
 | 
					            if 'points' not in entry and (entry['end_time'] - entry['start_time']) > self.reward_threshold:
 | 
				
			||||||
 | 
					                user.points_from_events += self.points
 | 
				
			||||||
 | 
					                entry['points'] = self.points
 | 
				
			||||||
 | 
					            db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @property
 | 
				
			||||||
 | 
					        def participants(self):
 | 
				
			||||||
 | 
					            return tuple(self.participants)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def __repr__(self):
 | 
				
			||||||
 | 
					            return '<Event {}>'.format(self.id)
 | 
				
			||||||
 | 
				
			|||||||
@ -50,9 +50,6 @@ footer {
 | 
				
			|||||||
    padding-bottom:80px;
 | 
					    padding-bottom:80px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#streams-online > .uk-article > a > h4 {
 | 
					 | 
				
			||||||
    margin:0px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#tsviewer > .uk-modal-dialog {
 | 
					#tsviewer > .uk-modal-dialog {
 | 
				
			||||||
    max-height: 80%;
 | 
					    max-height: 80%;
 | 
				
			||||||
    overflow-y: scroll;
 | 
					    overflow-y: scroll;
 | 
				
			||||||
@ -63,16 +60,21 @@ footer {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
.dn-streamer, .dn-streamer-offline {
 | 
					.dn-streamer, .dn-streamer-offline {
 | 
				
			||||||
    display: inline-block;
 | 
					    display: inline-block;
 | 
				
			||||||
    width: 110px;
 | 
					    width: 105px;
 | 
				
			||||||
    padding: 5px;
 | 
					    padding: 2px;
 | 
				
			||||||
    margin: 5px;
 | 
					    margin: 2px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#streams p.uk-text-bold {
 | 
				
			||||||
 | 
					    font-size: 12px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.dn-streamer-offline > img {
 | 
					.dn-streamer-offline > img {
 | 
				
			||||||
    height:50px;
 | 
					    height:50px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.dn-streamer-hover {
 | 
					.dn-streamer-hover {
 | 
				
			||||||
    background:red;
 | 
					    background:#CACACA;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.dn-hero-icon {
 | 
					.dn-hero-icon {
 | 
				
			||||||
@ -80,3 +82,19 @@ footer {
 | 
				
			|||||||
    padding:4px;
 | 
					    padding:4px;
 | 
				
			||||||
    margin:2px;
 | 
					    margin:2px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#streams {
 | 
				
			||||||
 | 
					    padding:10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#events_small > dl.uk-description-list-line > dt, #events_large > dl.uk-description-list-line > dt {
 | 
				
			||||||
 | 
					    border-top: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#events_small .uk-badge, #events_large .uk-badge {
 | 
				
			||||||
 | 
					    float:right;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#profile_links > a {
 | 
				
			||||||
 | 
					    font-size:14px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										26
									
								
								teamspeak.py
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								teamspeak.py
									
									
									
									
									
								
							@ -1,19 +1,35 @@
 | 
				
			|||||||
 | 
					from flask import url_for
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import operator
 | 
					import operator
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import ts3
 | 
					import ts3
 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
import requests
 | 
					import requests
 | 
				
			||||||
 | 
					from datetime import datetime, timedelta
 | 
				
			||||||
from xml.etree import ElementTree
 | 
					from xml.etree import ElementTree
 | 
				
			||||||
from flask import url_for
 | 
					 | 
				
			||||||
from bs4 import BeautifulSoup
 | 
					from bs4 import BeautifulSoup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from app import app
 | 
					from app import app, db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getTeamspeakWindow(window=605800):
 | 
					def getTeamspeakWindow(window=timedelta(weeks=1)):
 | 
				
			||||||
    current_time = time.time()
 | 
					    current_time = datetime.utcnow()
 | 
				
			||||||
    from models import TeamspeakData
 | 
					    from models import TeamspeakData
 | 
				
			||||||
    return TeamspeakData.query.filter(TeamspeakData.time < current_time, TeamspeakData.time > current_time-window).order_by(TeamspeakData.time).all()
 | 
					    return TeamspeakData.query.filter(TeamspeakData.time < current_time, TeamspeakData.time > current_time-window).order_by(TeamspeakData.time).all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def registerUserTeamspeakId(user, tsid):
 | 
				
			||||||
 | 
					    server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
 | 
				
			||||||
 | 
					    server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
 | 
				
			||||||
 | 
					    server.use(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    response = server.send_command('clientdbfind', {'pattern':tsid.encode('utf-8')}, ('uid',))
 | 
				
			||||||
 | 
					    if response.is_successful:
 | 
				
			||||||
 | 
					        cdbid = response.data[0]['cldbid']
 | 
				
			||||||
 | 
					        user.teamspeak_id = tsid
 | 
				
			||||||
 | 
					        sgid = [entry['sgid'] for entry in server.send_command('servergrouplist').data if entry['name'] == 'Normal' and entry['type'] == '1'][0]
 | 
				
			||||||
 | 
					        server.send_command('servergroupaddclient', {'sgid': sgid, 'cldbid': cdbid})
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_teamspeak_viewer():
 | 
					def create_teamspeak_viewer():
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
            server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
 | 
					            server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="uk-width-large-1-2 uk-width-medium-1-1 uk-text-center uk-panel botpad">
 | 
					    <div class="uk-width-large-1-2 uk-width-medium-1-1 uk-text-center uk-panel botpad">
 | 
				
			||||||
        <h2>Internet Friendlies:</h2>
 | 
					        <h2>Internet Friendlies:</h2>
 | 
				
			||||||
        <p>DotA related websites worth the occasional visit. We know they are no DotaNoobs, but we set a pretty high quality standard.</p>
 | 
					        <p>DotA related websites worth the occasional visit. We know they are no DotaNoobs, but we set a pretty high quality standard around here.</p>
 | 
				
			||||||
        <ul>
 | 
					        <ul>
 | 
				
			||||||
            <li><a href="http://www.reddit.com/r/DotA2/">Reddit's r/dota2</a></li>
 | 
					            <li><a href="http://www.reddit.com/r/DotA2/">Reddit's r/dota2</a></li>
 | 
				
			||||||
            <li><a href="http://www.dotainsight.com">DotaInsight Podcast</a></li>
 | 
					            <li><a href="http://www.dotainsight.com">DotaInsight Podcast</a></li>
 | 
				
			||||||
@ -26,10 +26,7 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="uk-width-large-1-2 uk-width-medium-1-1 uk-text-center uk-panel">
 | 
					    <div class="uk-width-large-1-2 uk-width-medium-1-1 uk-text-center uk-panel">
 | 
				
			||||||
        <h2>Streams We Like</h2>
 | 
					        <h2>Streams We Like</h2>
 | 
				
			||||||
        <ul id="streams-online">
 | 
					        <ul id="streams">
 | 
				
			||||||
        </ul>
 | 
					 | 
				
			||||||
        <hr id="stream-divider" class="uk-article-divider" style="display:none;" />
 | 
					 | 
				
			||||||
        <ul id="streams-offline">
 | 
					 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@ -38,34 +35,49 @@
 | 
				
			|||||||
{% block pagescripts %}
 | 
					{% block pagescripts %}
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
$(document).ready(function() {
 | 
					$(document).ready(function() {
 | 
				
			||||||
 | 
					        {% cache 60*5 %}
 | 
				
			||||||
	// Add the streams
 | 
						// Add the streams
 | 
				
			||||||
	var stream_url = "https://api.twitch.tv/kraken/streams/";
 | 
						var stream_url = "https://api.twitch.tv/kraken/streams/";
 | 
				
			||||||
	var channels = ["sheevergaming", "purgegamers", "synderen", "luminousinverse", "lddota"]
 | 
						var channels = ["2gd", "purgegamers", "synderen", "luminousinverse", "thegdstudio"]
 | 
				
			||||||
	for (var idx in channels) {
 | 
						for (var idx in channels) {
 | 
				
			||||||
		$.getJSON(stream_url+channels[idx]+"?callback=?", function(data) {
 | 
							$.getJSON(stream_url+channels[idx]+"?callback=?", function(data) {
 | 
				
			||||||
			if (data.stream) {
 | 
					                    if (data.stream) {
 | 
				
			||||||
				$('#streams-online').append("<article class='uk-article' id='" + data.stream.channel.name + "'>");
 | 
					                        var $a = $("<a href='"+data.stream.channel.url+"'></a>");
 | 
				
			||||||
				var jquery_selector = '#'+data.stream.channel.name;
 | 
					                        var $strm = $("<div class='dn-streamer uk-text-success uk-panel uk-panel-box' id='"+data.stream.channel.name+"'></div>");
 | 
				
			||||||
                                $(jquery_selector).append("<a href='"+data.stream.channel.url+"'><h4>" + data.stream.channel.display_name + "</h4></a>")
 | 
					
 | 
				
			||||||
				var span_text = "<p class='uk-article-meta'>";
 | 
					                        $strm.append("<p class='uk-text-bold'>" + data.stream.channel.display_name + "</p>");
 | 
				
			||||||
				span_text = span_text + "Playing: " + data.stream.game  + "<br />";
 | 
					                        $strm.append("<img src='" + data.stream.preview.small + "' />");
 | 
				
			||||||
				span_text = span_text + "Viewers: " + data.stream.viewers + "<br />";
 | 
					                        $strm.append("<p><i class='uk-icon-male'></i> "+data.stream.viewers+"</p>");
 | 
				
			||||||
				span_text = span_text + "</p>";
 | 
					
 | 
				
			||||||
				$(jquery_selector).append(span_text);
 | 
					                        $a.append($strm);
 | 
				
			||||||
				$(jquery_selector).append("<img src='" + data.stream.preview.medium + "' class='' />")
 | 
					                        $("#streams").prepend($a);
 | 
				
			||||||
				$('#streams-online').append("</article>");
 | 
					
 | 
				
			||||||
                                $('#stream-divider').show();
 | 
					                    } else {
 | 
				
			||||||
			} else {
 | 
					                        $.getJSON(data._links.channel+"?callback=?", function(data) {
 | 
				
			||||||
				$.getJSON(data._links.channel+"?callback=?", function(data) {
 | 
					                            var $a = $("<a href='"+data.url+"'></a>");
 | 
				
			||||||
					$('#streams-offline').append("<article class='uk-article' id='" + data.name + "'>");
 | 
					                            var $strm = $("<div class='dn-streamer-offline uk-text-success uk-panel uk-panel-box' id='"+data.name+"'></div>");
 | 
				
			||||||
                                        $('#'+data.name).append("<a href='"+data.url+"'><h4>" + data.display_name + "</h4></a>");
 | 
					
 | 
				
			||||||
					$('#'+data.name).append("<img src='" + data.logo + "' style='float: right;' width='62' height='62' /><br />");
 | 
					                            $strm.append("<p class='uk-text-bold'>" + data.display_name + "</p>");
 | 
				
			||||||
					$('#'+data.name).append("<p class='uk-article-meta'><strong>Offline</strong></p>");
 | 
					                            $strm.append("<img src='" + data.logo + "' />");
 | 
				
			||||||
					$('#streams-offline').append("</div>");
 | 
					                            $strm.append("<p class='dn-offline'>Offline</p>");
 | 
				
			||||||
				});
 | 
					
 | 
				
			||||||
			}
 | 
					                            $a.append($strm);
 | 
				
			||||||
 | 
					                            $("#streams").append($a);
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        {% endcache %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $("#streams").on({
 | 
				
			||||||
 | 
					            mouseover: function() {
 | 
				
			||||||
 | 
					                $(this).addClass('dn-streamer-hover');
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            mouseleave: function() {
 | 
				
			||||||
 | 
					                $(this).removeClass('dn-streamer-hover');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }, "div");
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,32 +5,16 @@
 | 
				
			|||||||
{% block title %}Dota Noobs{% endblock %}
 | 
					{% block title %}Dota Noobs{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
{#{% cache 60*5 %}#}
 | 
					{% cache 60*5 %}
 | 
				
			||||||
{% set teamspeak_data = get_teamspeak_window() %}
 | 
					{% set teamspeak_data = get_teamspeak_window() %}
 | 
				
			||||||
 | 
					{% set latest_news = get_latest_news() %}
 | 
				
			||||||
<div class="uk-grid">
 | 
					<div class="uk-grid">
 | 
				
			||||||
    <div class="uk-width-large-1-2 uk-width-medium-1-1 uk-panel uk-panel-space">
 | 
					
 | 
				
			||||||
        <h1 class="uk-panel-title">Events</h1>
 | 
					    <div id="events_large" class="uk-width-1-2 uk-visible-large uk-panel uk-panel-space">
 | 
				
			||||||
        {#
 | 
					        {% include "events_widget.html" %}
 | 
				
			||||||
        {% if active_event %}
 | 
					 | 
				
			||||||
        <article class="uk-article"> 
 | 
					 | 
				
			||||||
            <h4>Right Now</h4>
 | 
					 | 
				
			||||||
            <a href="{{ url_for('event_summary', eventid=active_event._id) }}">{{ active_event.name }}</a>
 | 
					 | 
				
			||||||
            <p class="uk-article-meta">Ends at: {{ timestamp_to_js_date(active_event.end_time) }}</p>
 | 
					 | 
				
			||||||
        </article>
 | 
					 | 
				
			||||||
        {% endif %}
 | 
					 | 
				
			||||||
        {% if upcoming_event %}
 | 
					 | 
				
			||||||
        <article class="uk-article">
 | 
					 | 
				
			||||||
            <h4>Next Event</h4>
 | 
					 | 
				
			||||||
            <a href="{{ url_for('event_summary', eventid=upcoming_event._id) }}">{{ upcoming_event.name }}</a>
 | 
					 | 
				
			||||||
            <p class="uk-article-meta">Starts at: {{ timestamp_to_js_date(upcoming_event.start_time) }}</p>
 | 
					 | 
				
			||||||
        </article>
 | 
					 | 
				
			||||||
        {% else %}
 | 
					 | 
				
			||||||
            <em>No events planned for the near future. Suggest one on the forum!</em>
 | 
					 | 
				
			||||||
        {% endif %}
 | 
					 | 
				
			||||||
        #}
 | 
					 | 
				
			||||||
        <em>No events planned for the near future. Suggest one on the forum!</em>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="uk-width-large-1-2 uk-width-medium-1-1 uk-panel uk-panel-box uk-text-center">
 | 
					
 | 
				
			||||||
 | 
					    <div id="teamspeak" class="uk-width-large-1-2 uk-width-medium-1-1 uk-panel uk-panel-box uk-text-center">
 | 
				
			||||||
        <a href="#" data-uk-modal="{target: '#tsviewer'}"><div class="uk-badge uk-panel-badge uk-badge-success"><i class="uk-icon-user"></i> Users</div></a>
 | 
					        <a href="#" data-uk-modal="{target: '#tsviewer'}"><div class="uk-badge uk-panel-badge uk-badge-success"><i class="uk-icon-user"></i> Users</div></a>
 | 
				
			||||||
        <h1 class="uk-panel-title">Teamspeak</h1>
 | 
					        <h1 class="uk-panel-title">Teamspeak</h1>
 | 
				
			||||||
        <div class="uk-grid uk-margin-bottom">
 | 
					        <div class="uk-grid uk-margin-bottom">
 | 
				
			||||||
@ -57,11 +41,15 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div id="streams" class="uk-width-1-1 uk-text-center uk-panel uk-panel-space">
 | 
					    <div id="events_small" class="uk-width-1-1 uk-hidden-large uk-panel uk-panel-space">
 | 
				
			||||||
 | 
					        {% include "events_widget.html" %}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    <div id="streams" class="uk-width-1-1 uk-text-center uk-panel">
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="uk-width-1-1 uk-panel uk-panel-header">
 | 
					    <div class="uk-width-1-1 uk-panel uk-panel-header uk-panel-space">
 | 
				
			||||||
        <h4 class="uk-panel-title">News and Announcements</h4>
 | 
					        <h1 class="uk-panel-title">News and Announcements</h1>
 | 
				
			||||||
        {% for news in latest_news %}
 | 
					        {% for news in latest_news %}
 | 
				
			||||||
            <article class="uk-article dn-news-article">
 | 
					            <article class="uk-article dn-news-article">
 | 
				
			||||||
            <h4 class="uk-article-title" title="{{ news['title'] }}"><a href="{{ news['url'] }}">{{ news['title'] }}</a></h4>
 | 
					            <h4 class="uk-article-title" title="{{ news['title'] }}"><a href="{{ news['url'] }}">{{ news['title'] }}</a></h4>
 | 
				
			||||||
@ -70,15 +58,22 @@
 | 
				
			|||||||
            </article>
 | 
					            </article>
 | 
				
			||||||
        {% endfor %}
 | 
					        {% endfor %}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#{% endcache %}#}
 | 
					{% endcache %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block pagescripts %}
 | 
					{% block pagescripts %}
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
{% cache 60*5 %}
 | 
					 | 
				
			||||||
$(document).ready(function() {
 | 
					$(document).ready(function() {
 | 
				
			||||||
 | 
					        if ($('#events_large > dl').length < 1) {
 | 
				
			||||||
 | 
					            var msg = "<h2>Events</h2><em>No events planned for the near future. Suggest one on the forum!</em>"
 | 
				
			||||||
 | 
					            $('#events_small').append(msg);
 | 
				
			||||||
 | 
					            $('#events_large').append(msg);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {% cache 60*5 %}
 | 
				
			||||||
	// Add the streams
 | 
						// Add the streams
 | 
				
			||||||
	var stream_url = "https://api.twitch.tv/kraken/streams/";
 | 
						var stream_url = "https://api.twitch.tv/kraken/streams/";
 | 
				
			||||||
        var channels = ["dotanoobs", "bearhugdota", "kreejaffakree", "prettypenguins", "shaneomad"];
 | 
					        var channels = ["dotanoobs", "bearhugdota", "kreejaffakree", "prettypenguins", "shaneomad"];
 | 
				
			||||||
@ -113,7 +108,7 @@ $(document).ready(function() {
 | 
				
			|||||||
        {% endcache %}
 | 
					        {% endcache %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        $(".dn-streamer, .dn-streamer-offline").on({
 | 
					        $("#streams").on({
 | 
				
			||||||
            mouseover: function() {
 | 
					            mouseover: function() {
 | 
				
			||||||
                $(this).addClass('dn-streamer-hover');
 | 
					                $(this).addClass('dn-streamer-hover');
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -121,12 +116,6 @@ $(document).ready(function() {
 | 
				
			|||||||
                $(this).removeClass('dn-streamer-hover');
 | 
					                $(this).removeClass('dn-streamer-hover');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }, "div");
 | 
					        }, "div");
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Localize the events
 | 
					 | 
				
			||||||
	$('.date').each( function( index ) {
 | 
					 | 
				
			||||||
		var d = new Date($(this).text());
 | 
					 | 
				
			||||||
		$(this).text( d.toLocaleDateString() + ' @ ' + d.toLocaleTimeString() );
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,13 +10,14 @@
 | 
				
			|||||||
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
					        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- CSS includes -->
 | 
					        <!-- CSS includes -->
 | 
				
			||||||
        <!--<link rel="stylesheet" href="{{ url_for('static', filename='css/uikit.min.css') }}" />-->
 | 
					        <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/uikit/2.4.0/css/uikit.gradient.min.css" />
 | 
				
			||||||
        <link rel="stylesheet" href="{{ url_for('static', filename='css/uikit.gradient.min.css') }}" />
 | 
					 | 
				
			||||||
        <link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}" />
 | 
					        <link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- Javascript includes -->
 | 
					        <!-- Javascript includes -->
 | 
				
			||||||
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
 | 
					        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
 | 
				
			||||||
        <script src="{{ url_for('static', filename='js/uikit.min.js') }}"></script>
 | 
					        <script src="//cdnjs.cloudflare.com/ajax/libs/uikit/2.4.0/js/uikit.min.js"></script>
 | 
				
			||||||
 | 
					        <script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.5.1/moment.min.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </head>
 | 
					    </head>
 | 
				
			||||||
    <body>
 | 
					    <body>
 | 
				
			||||||
        <!-- Navigation bar -->
 | 
					        <!-- Navigation bar -->
 | 
				
			||||||
@ -33,25 +34,27 @@
 | 
				
			|||||||
                    <li><a href="{{ url_for('user_profile', userid=g.user.id) }}">Profile</a></li>
 | 
					                    <li><a href="{{ url_for('user_profile', userid=g.user.id) }}">Profile</a></li>
 | 
				
			||||||
                    <li><a href="{{ url_for('user_random_hero', userid=g.user.id) }}">A-Z Challenge</a></li>
 | 
					                    <li><a href="{{ url_for('user_random_hero', userid=g.user.id) }}">A-Z Challenge</a></li>
 | 
				
			||||||
                    <li><a href="http://board.dotanoobs.com/?page=lastposts">Latest Posts</a></li>
 | 
					                    <li><a href="http://board.dotanoobs.com/?page=lastposts">Latest Posts</a></li>
 | 
				
			||||||
 | 
					                    {% if g.user.admin %}
 | 
				
			||||||
 | 
					                    <li><a href="{{ url_for('event_edit') }}">Add Event</a></li>
 | 
				
			||||||
 | 
					                    {% endif %}
 | 
				
			||||||
                    <li class="uk-nav-divider"></li>
 | 
					                    <li class="uk-nav-divider"></li>
 | 
				
			||||||
                    <li><a href="{{ url_for('user_settings', userid=g.user.id) }}">Settings</a></li>
 | 
					                    <li><a href="{{ url_for('user_settings') }}">Settings</a></li>
 | 
				
			||||||
                    <li><a href="{{ url_for('logout') }}">Logout</a></li>
 | 
					                    <li><a href="{{ url_for('logout') }}">Logout</a></li>
 | 
				
			||||||
                </ul>
 | 
					                </ul>
 | 
				
			||||||
           </div>
 | 
					           </div>
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
        {% else %}
 | 
					        {% else %}
 | 
				
			||||||
        <a class="uk-navbar-flip uk-navbar-content" href="{{ url_for('login') }}"><img src="http://cdn.steamcommunity.com/public/images/signinthroughsteam/sits_large_border.png" /></a>
 | 
					        <a class="uk-navbar-flip uk-navbar-content" href="{{ url_for('login') }}"><img src="http://steamcommunity-a.akamaihd.net/public/images/signinthroughsteam/sits_large_border.png" /></a>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
        <div class="uk-navbar-content uk-navbar-center uk-hidden-small uk-text-bold">DotaNoobs</div>
 | 
					        <div class="uk-navbar-content uk-navbar-center uk-hidden-small uk-text-bold">DotaNoobs</div>
 | 
				
			||||||
        </nav>
 | 
					        </nav>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- Flash Error Messages -->
 | 
					        <!-- Flash Error Messages -->
 | 
				
			||||||
        {% with messages = get_flashed_messages() %}
 | 
					        {% with messages = get_flashed_messages(with_categories=true) %}
 | 
				
			||||||
        {% if messages %}
 | 
					        {% if messages %}
 | 
				
			||||||
        <ul class="flashes uk-width-1-3 uk-container-center">
 | 
					        <ul class="uk-list flashes uk-width-2-3  uk-container-center">
 | 
				
			||||||
            <a href="" class="uk-alert-close uk-close"></a>
 | 
					            {% for category, message in messages %}
 | 
				
			||||||
            {% for message in messages %}
 | 
					            <li class="uk-alert uk-alert-{{ category }}">{{ message }} <a href="#" class="uk-alert-close uk-close"></a> </li>
 | 
				
			||||||
            <li class="uk-alert uk-alert-danger">{{ message }}</li>
 | 
					 | 
				
			||||||
            {% endfor %}
 | 
					            {% endfor %}
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
@ -60,7 +63,9 @@
 | 
				
			|||||||
        <!-- Start Main Container -->
 | 
					        <!-- Start Main Container -->
 | 
				
			||||||
        <div id="container" class="uk-grid">
 | 
					        <div id="container" class="uk-grid">
 | 
				
			||||||
            <!-- Big top logo -->
 | 
					            <!-- Big top logo -->
 | 
				
			||||||
 | 
					            {% if not g.user.logo %}
 | 
				
			||||||
            <div class="uk-width-1-1"><img class="uk-align-center" id="biglogo" src="{{ url_for('static', filename='img/biglogo.png') }}"></div>
 | 
					            <div class="uk-width-1-1"><img class="uk-align-center" id="biglogo" src="{{ url_for('static', filename='img/biglogo.png') }}"></div>
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
            <!-- Side navigation -->
 | 
					            <!-- Side navigation -->
 | 
				
			||||||
            <div class="uk-visible-large uk-width-1-5 uk-panel">
 | 
					            <div class="uk-visible-large uk-width-1-5 uk-panel">
 | 
				
			||||||
                {% if g.doob%}
 | 
					                {% if g.doob%}
 | 
				
			||||||
@ -78,9 +83,10 @@
 | 
				
			|||||||
                    {% endif %}
 | 
					                    {% endif %}
 | 
				
			||||||
                    <ul class="uk-nav uk-nav-offcanvas" data-uk-nav>
 | 
					                    <ul class="uk-nav uk-nav-offcanvas" data-uk-nav>
 | 
				
			||||||
                        {% include 'sidenav.html' %}
 | 
					                        {% include 'sidenav.html' %}
 | 
				
			||||||
                </ul>
 | 
					                    </ul>
 | 
				
			||||||
            </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            <!-- Main content area -->
 | 
					            <!-- Main content area -->
 | 
				
			||||||
            <div class="uk-width-large-4-5 uk-width-medium-5-5">
 | 
					            <div class="uk-width-large-4-5 uk-width-medium-5-5">
 | 
				
			||||||
                {% block content %}
 | 
					                {% block content %}
 | 
				
			||||||
@ -91,6 +97,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        <!-- Footer section -->
 | 
					        <!-- Footer section -->
 | 
				
			||||||
        <footer class="uk-clearfix uk-align-center">
 | 
					        <footer class="uk-clearfix uk-align-center">
 | 
				
			||||||
 | 
					        {% cache 60*5 %}
 | 
				
			||||||
        <div class="uk-float-left uk-visible-large">
 | 
					        <div class="uk-float-left uk-visible-large">
 | 
				
			||||||
            <a href="http://flask.pocoo.org/"><img src="{{ url_for('static', filename='img/powered-by-flask-s.png') }}" alt="Flask"></a> &
 | 
					            <a href="http://flask.pocoo.org/"><img src="{{ url_for('static', filename='img/powered-by-flask-s.png') }}" alt="Flask"></a> &
 | 
				
			||||||
            <a href="http://store.steampowered.com/"><img src="{{ url_for('static', filename='img/steam.png') }}" alt="Steam"></a>
 | 
					            <a href="http://store.steampowered.com/"><img src="{{ url_for('static', filename='img/steam.png') }}" alt="Steam"></a>
 | 
				
			||||||
@ -101,10 +108,23 @@
 | 
				
			|||||||
            <a href="http://www.youtube.com/user/DotaNoobsVods"><img src="{{ url_for('static', filename='img/youtube.png') }}" alt="YouTube" /></a>
 | 
					            <a href="http://www.youtube.com/user/DotaNoobsVods"><img src="{{ url_for('static', filename='img/youtube.png') }}" alt="YouTube" /></a>
 | 
				
			||||||
            <a href="emailto:admin@dotanoobs.com"><img src="{{ url_for('static', filename='img/email.png') }}" /></a>
 | 
					            <a href="emailto:admin@dotanoobs.com"><img src="{{ url_for('static', filename='img/email.png') }}" /></a>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					        {% endcache %}
 | 
				
			||||||
        </footer>
 | 
					        </footer>
 | 
				
			||||||
        <!-- Page-specific javascript here -->
 | 
					        <!-- Page-specific javascript here -->
 | 
				
			||||||
        {% block pagescripts %}
 | 
					        {% block pagescripts %}
 | 
				
			||||||
        {% endblock %}
 | 
					        {% endblock %}
 | 
				
			||||||
 | 
					        <script type='text/javascript'>
 | 
				
			||||||
 | 
					            $(document).ready(function() {
 | 
				
			||||||
 | 
					                $("li.uk-alert > a.uk-alert-close").on('click', function(){
 | 
				
			||||||
 | 
					                    $(this).parent().hide();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                $(document).ready(function() {
 | 
				
			||||||
 | 
					                    $('.date').each(function (index) {
 | 
				
			||||||
 | 
					                        var d = moment.utc($(this).text()+" UTC");
 | 
				
			||||||
 | 
					                        $(this).html(d.local().format("h:mm A on MMM Do"));
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        </script>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -7,22 +7,31 @@
 | 
				
			|||||||
    <div class="uk-width-2-3">
 | 
					    <div class="uk-width-2-3">
 | 
				
			||||||
        <h2 class="uk-float-left"><img class="" src="{{ user.avatar }}" /> {{ user.nickname }}</h2>
 | 
					        <h2 class="uk-float-left"><img class="" src="{{ user.avatar }}" /> {{ user.nickname }}</h2>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="uk-width-1-3 uk-text-center">
 | 
					    <div id="profile_links" class="uk-width-1-3 uk-text-center">
 | 
				
			||||||
        <a href="http://steamcommunity.com/profiles/{{ user.steam_id | safe }}">Steam</a> | 
 | 
					        <div class="uk-panel">
 | 
				
			||||||
        <a href="http://board.dotanoobs.com/?page=profile&id={{ user.id | safe }}">Forum Profile</a> |
 | 
					            {% if user.public %}
 | 
				
			||||||
        <a href="http://dotabuff.com/search?q={{ user.steam_id }}">Dotabuff</a>
 | 
					            <a href="http://steamcommunity.com/profiles/{{ user.steam_id | safe }}">Steam</a> | 
 | 
				
			||||||
 | 
					            <a href="http://board.dotanoobs.com/?page=profile&id={{ user.id | safe }}">Forum Profile</a> |
 | 
				
			||||||
 | 
					            <a href="http://dotabuff.com/search?q={{ user.steam_id }}">Dotabuff</a>
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <!--Main content area -->
 | 
					    <!--Main content area -->
 | 
				
			||||||
    <div class="uk-width-large-2-3 uk-width-medium-1-1 uk-panel">
 | 
					    <div class="uk-width-large-2-3 uk-width-medium-1-1 uk-panel">
 | 
				
			||||||
 | 
					    {% if user.public %}
 | 
				
			||||||
        {% if user.bio_text == None %}
 | 
					        {% if user.bio_text == None %}
 | 
				
			||||||
        <em class="uk-text-danger">This user's profile bio is empty!</em>
 | 
					        <em class="uk-text-danger">This user's profile bio is empty!</em>
 | 
				
			||||||
        {% else %}
 | 
					        {% else %}
 | 
				
			||||||
        <em class="uk-text-bold">{{ user.bio_text }}</em>
 | 
					        <em class="uk-text-bold">{{ user.bio_text }}</em>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					    {% else %}
 | 
				
			||||||
 | 
					        <em class="uk-text-danger">This user profile is set to private</em>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
        {% if user.id == g.user.id %} <a href="{{ url_for('user_settings')}}"><i class="uk-icon-edit"></i></a>{% endif %}
 | 
					        {% if user.id == g.user.id %} <a href="{{ url_for('user_settings')}}"><i class="uk-icon-edit"></i></a>{% endif %}
 | 
				
			||||||
    </div>
 | 
					    </div> 
 | 
				
			||||||
    <!-- Side bar -->
 | 
					    <!-- Side bar -->
 | 
				
			||||||
    <div class="uk-width-large-1-3 uk-width-medium-1-1 uk-panel uk-panel-box uk-panel-box-secondary">
 | 
					    <div class="uk-width-large-1-3 uk-width-medium-1-1 uk-panel uk-panel-box uk-panel-box-secondary">
 | 
				
			||||||
 | 
					        {% if user.public %}
 | 
				
			||||||
        <div class="uk-container-center uk-text-center">
 | 
					        <div class="uk-container-center uk-text-center">
 | 
				
			||||||
            <span class="uk-text-bold">Current Hero</span><br/>
 | 
					            <span class="uk-text-bold">Current Hero</span><br/>
 | 
				
			||||||
            <span>{{ user.random_hero['localized_name'] }}</span><br/>
 | 
					            <span>{{ user.random_hero['localized_name'] }}</span><br/>
 | 
				
			||||||
@ -31,11 +40,13 @@
 | 
				
			|||||||
                <span>View A-Z Progress</span>
 | 
					                <span>View A-Z Progress</span>
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <ul class="uk-list uk-list-space uk-list-striped">
 | 
					        <ul class="uk-list uk-list-space uk-list-striped uk-text-center uk-text-small">
 | 
				
			||||||
            <li>Points: <span id='points_total'>0</span></li>
 | 
					            <li>Completed <span id='rands'>{{ user.random_heroes.completed | length }}</span> heroes in A-Z</li>
 | 
				
			||||||
            <li>Last Seen: <span id='date'></span></li>
 | 
					            <li>Has <span id='points_total'>0</span> doobs points</li>
 | 
				
			||||||
            <li>Heroes Randomed: <span id='rands'>{{ user.random_heroes.completed | length }}</span></li>
 | 
					            <li>Last seen at <span class='date'> {{ user.last_seen | js_datetime }}</span></li>
 | 
				
			||||||
 | 
					            <li>Doob since <span class='date'> {{ user.created | js_datetime }}</span></li>
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,21 +5,20 @@
 | 
				
			|||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
<div class="uk-grid" data-uk-grid-margin>
 | 
					<div class="uk-grid" data-uk-grid-margin>
 | 
				
			||||||
    <div class="uk-width-2-3">
 | 
					    <div class="uk-width-2-3">
 | 
				
			||||||
        <h2 class="uk-float-left"><img class="" src="{{ user.avatar }}" /> {{ user.nickname }}</h2>
 | 
					        <h2 class="uk-float-left"><img class="" src="{{ g.user.avatar }}" /> {{ g.user.nickname }}'s Settings</h2>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="uk-width-1-3 uk-text-center">
 | 
					    <div class="uk-width-1-3 uk-text-center">
 | 
				
			||||||
 | 
					        <a href="{{ url_for('enable_statistics') }}" class="uk-button uk-button-danger">Enable Statistics <i class="uk-icon-star"></i></a>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <!--Main content area -->
 | 
					    <!--Main content area -->
 | 
				
			||||||
    <div class="uk-width-large-2-3 uk-width-medium-1-1 uk-panel">
 | 
					    <div class="uk-width-1-1 uk-panel">
 | 
				
			||||||
        <form class="uk-form uk-form-width-large" action="" method="post" name="settings">
 | 
					        <form class="uk-form uk-form-width-large" action="" method="post" name="settings">
 | 
				
			||||||
            {{ form.hidden_tag() }}
 | 
					            {{ form.hidden_tag() }}
 | 
				
			||||||
            <fieldset data-uk-margin>
 | 
					            <fieldset data-uk-margin>
 | 
				
			||||||
                <legend>Settings</legend>
 | 
					 | 
				
			||||||
                <div class="uk-form-row">
 | 
					                <div class="uk-form-row">
 | 
				
			||||||
                    <ul class="uk-list">
 | 
					                    <ul class="uk-list">
 | 
				
			||||||
                        <li><label class="uk-form-label"> {{ form.public }} Public Profile</label></li>
 | 
					                        <li><label class="uk-form-label"> {{ form.public }} Public Profile</label></li>
 | 
				
			||||||
                        <li><label class="uk-form-label"><input type="checkbox" disabled> Show Big Logo</label></li>
 | 
					                        <li><label class="uk-form-label"> {{ form.logo }} Hide Big Logo</label></li>
 | 
				
			||||||
                        <li><label class="uk-form-label"><input type="checkbox" disabled> Nonexistant Setting</label></li>
 | 
					 | 
				
			||||||
                    </ul>
 | 
					                    </ul>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="uk-form-row">
 | 
					                <div class="uk-form-row">
 | 
				
			||||||
 | 
				
			|||||||
@ -17,15 +17,16 @@
 | 
				
			|||||||
    </li>
 | 
					    </li>
 | 
				
			||||||
    <li class="uk-nav-divider"></li>
 | 
					    <li class="uk-nav-divider"></li>
 | 
				
			||||||
    <li class="uk-nav-header">Social</li>
 | 
					    <li class="uk-nav-header">Social</li>
 | 
				
			||||||
    <li><a href="http://board.dotanoobs.com"><i class="uk-icon-group"> Board</i></a></li>
 | 
					    <li><a href="http://board.dotanoobs.com"><i class="uk-icon-group"></i> Board</a></li>
 | 
				
			||||||
    <li><a href="http://www.youtube.com/user/DotaNoobsVods"><i class="uk-icon-youtube"> YouTube</i></a></li>
 | 
					    <li><a href="http://www.youtube.com/user/DotaNoobsVods"><i class="uk-icon-youtube"></i> YouTube</a></li>
 | 
				
			||||||
    <li><a href="http://webchat.oftc.net/?channels=dotanoobs&uio=d4"><i class="uk-icon-comments-alt"> IRC Chat</i></a></li>
 | 
					    <li><a href="http://webchat.oftc.net/?channels=dotanoobs&uio=d4"><i class="uk-icon-comments"></i> IRC Chat</a></li>
 | 
				
			||||||
    <li class="uk-nav-divider"></li>
 | 
					    <li class="uk-nav-divider"></li>
 | 
				
			||||||
 | 
					    <li class="uk-nav-header">Controls</li>
 | 
				
			||||||
    {% if not g.user%}
 | 
					    {% if not g.user%}
 | 
				
			||||||
    <li><a href="{{ url_for('login') }}"><i class="uk-icon-off"> Login</i></a></li>
 | 
					    <li><a href="{{ url_for('login') }}"><i class="uk-icon-sign-in"></i> Login</a></li>
 | 
				
			||||||
    <li><a href="{{ url_for('login') }}"><i class="uk-icon-cog"> Register</i></a></li>
 | 
					    <li><a href="{{ url_for('login') }}"><i class="uk-icon-star"></i> Register</a></li>
 | 
				
			||||||
    {% else %}
 | 
					    {% else %}
 | 
				
			||||||
    <li {% if request.endpoint == 'user_profile' %} class='uk-active' {% endif %}><a href="{{ url_for('user_profile', userid=g.user.id) }}"><i class="uk-icon-home"> Profile</i></a></li>
 | 
					    <li {% if request.endpoint == 'user_profile' %} class='uk-active' {% endif %}><a href="{{ url_for('user_profile', userid=g.user.id) }}"><i class="uk-icon-dashboard"></i> Profile</a></li>
 | 
				
			||||||
    <li><a href="{{ url_for('user_settings', userid=g.user.id) }}"><i class="uk-icon-cog"> Settings</i></a></li>
 | 
					    <li {% if request.endpoint == 'user_settings' %} class='uk-active' {% endif %}><a href="{{ url_for('user_settings') }}"><i class="uk-icon-cogs"></i> Settings</a></li>
 | 
				
			||||||
    <li><a href="{{ url_for('logout') }}"><i class="uk-icon-off"> Logout</i></a></li>
 | 
					    <li><a href="{{ url_for('logout') }}"><i class="uk-icon-sign-out"></i> Logout</a></li>
 | 
				
			||||||
    {% endif %}
 | 
					    {% endif %}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,9 +13,9 @@
 | 
				
			|||||||
        <h3 class="uk-text-bold uk-text-center">Recent Activity</h3>
 | 
					        <h3 class="uk-text-bold uk-text-center">Recent Activity</h3>
 | 
				
			||||||
        <div class="uk-panel">
 | 
					        <div class="uk-panel">
 | 
				
			||||||
            <ul>
 | 
					            <ul>
 | 
				
			||||||
                <li>Active users connected: <span id="unique_clients"></span></li>
 | 
					                <li>Users currently connected:  <span id="current_clients"></span></li>
 | 
				
			||||||
                <li>Total users connected:  <span id="current_clients">{{ ts3_current_clients() }}</span></li>
 | 
					                <li>Unique users this week: <span id="unique_clients"></span></li>
 | 
				
			||||||
                <li>Countries active on server: <span id="country_clients"></span></li>
 | 
					                <li>Countries active this week: <span id="country_clients"></span></li>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="uk-panel" id="teamspeak_active_users"></div>
 | 
					        <div class="uk-panel" id="teamspeak_active_users"></div>
 | 
				
			||||||
        <div class="uk-panel" id="teamspeak_map"></div>
 | 
					        <div class="uk-panel" id="teamspeak_map"></div>
 | 
				
			||||||
@ -38,13 +38,14 @@
 | 
				
			|||||||
{% block pagescripts %}
 | 
					{% block pagescripts %}
 | 
				
			||||||
{% cache 60*5 %}
 | 
					{% cache 60*5 %}
 | 
				
			||||||
{% set teamspeak_data = get_teamspeak_window() %}
 | 
					{% set teamspeak_data = get_teamspeak_window() %}
 | 
				
			||||||
<script src="http://code.highcharts.com/3.0.1/highcharts.js"></script>
 | 
					<script src="//cdnjs.cloudflare.com/ajax/libs/highcharts/3.0.7/highcharts.js"></script>
 | 
				
			||||||
<script type="text/javascript" src="http://github.highcharts.com/75c66eb3/modules/map.src.js"></script>
 | 
					<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/highcharts/3.0.7/modules/map.src.js"></script>
 | 
				
			||||||
<script type="text/javascript" src="http://github.highcharts.com/75c66eb3/modules/data.src.js"></script>
 | 
					<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/highcharts/3.0.7/modules/data.src.js"></script>
 | 
				
			||||||
<script type="text/javascript" src="{{ url_for('static', filename='js/world-map-shapes.js') }}"></script>
 | 
					<script type="text/javascript" src="{{ url_for('static', filename='js/world-map-shapes.js') }}"></script>
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
$(document).ready(function() {
 | 
					$(document).ready(function() {
 | 
				
			||||||
	$('#unique_clients').html("{{ ts3_active_clients(teamspeak_data) }}");
 | 
						$('#unique_clients').html("{{ ts3_active_clients(teamspeak_data) }}");
 | 
				
			||||||
 | 
						$('#current_clients').html("{{ ts3_current_clients() }}");
 | 
				
			||||||
	$('#country_clients').html("{{ ts3_countries_active(teamspeak_data) }}");
 | 
						$('#country_clients').html("{{ ts3_countries_active(teamspeak_data) }}");
 | 
				
			||||||
	Highcharts.setOptions({
 | 
						Highcharts.setOptions({
 | 
				
			||||||
		global: {
 | 
							global: {
 | 
				
			||||||
@ -90,7 +91,7 @@ $(document).ready(function() {
 | 
				
			|||||||
			type: 'areaspline',
 | 
								type: 'areaspline',
 | 
				
			||||||
			data: [
 | 
								data: [
 | 
				
			||||||
				{% for data in teamspeak_data %}
 | 
									{% for data in teamspeak_data %}
 | 
				
			||||||
					[new Date('{{ timestamp_to_js_date(data.time) }}').valueOf(), {{ data.clients | count }}],
 | 
					                                        [new Date('{{ data.time | js_datetime }}').valueOf(), {{ data.clients | count }}],
 | 
				
			||||||
				{% endfor %}
 | 
									{% endfor %}
 | 
				
			||||||
			],
 | 
								],
 | 
				
			||||||
		}],
 | 
							}],
 | 
				
			||||||
@ -155,7 +156,7 @@ $(document).ready(function() {
 | 
				
			|||||||
		map_options.series[0].data.push({
 | 
							map_options.series[0].data.push({
 | 
				
			||||||
			y: num,
 | 
								y: num,
 | 
				
			||||||
			name: country_names[key],
 | 
								name: country_names[key],
 | 
				
			||||||
			path: Highcharts.pathToArray(shapes[key]),
 | 
								path: shapes[key],
 | 
				
			||||||
			states: {
 | 
								states: {
 | 
				
			||||||
				hover: {
 | 
									hover: {
 | 
				
			||||||
					color: '#FF7F00'
 | 
										color: '#FF7F00'
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										27
									
								
								utils.py
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								utils.py
									
									
									
									
									
								
							@ -7,6 +7,7 @@ from os import path, makedirs
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from calendar import timegm
 | 
					from calendar import timegm
 | 
				
			||||||
from app import app, cache
 | 
					from app import app, cache
 | 
				
			||||||
 | 
					from board import latest_news
 | 
				
			||||||
from teamspeak import create_teamspeak_viewer, getTeamspeakWindow, ISO3166_MAPPING
 | 
					from teamspeak import create_teamspeak_viewer, getTeamspeakWindow, ISO3166_MAPPING
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_steam_userinfo(steam_id):
 | 
					def get_steam_userinfo(steam_id):
 | 
				
			||||||
@ -55,6 +56,22 @@ def shorten_filter(s, num_words=40):
 | 
				
			|||||||
		output += '...'
 | 
							output += '...'
 | 
				
			||||||
	return output
 | 
						return output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.template_filter('js_datetime')
 | 
				
			||||||
 | 
					def js_datetime(dt):
 | 
				
			||||||
 | 
					    return dt.strftime('%m %d %Y %H:%M')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.template_filter('event_badge')
 | 
				
			||||||
 | 
					def event_badge(t):
 | 
				
			||||||
 | 
					    if t == 'coaching':
 | 
				
			||||||
 | 
					        badge = "<div class='uk-badge'>Coaching</div>"
 | 
				
			||||||
 | 
					    elif t == 'inhouse':
 | 
				
			||||||
 | 
					        badge = "<div class='uk-badge uk-badge-success'>Inhouse</div>"
 | 
				
			||||||
 | 
					    elif t == 'tournament':
 | 
				
			||||||
 | 
					        badge = "<div class='uk-badge uk-badge-danger'>Tournament</div>"
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        badge = "<div class='uk-badge uk-badge-warning'>Other</div>"
 | 
				
			||||||
 | 
					    return badge;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.context_processor
 | 
					@app.context_processor
 | 
				
			||||||
def utility_processor():
 | 
					def utility_processor():
 | 
				
			||||||
    ''' For Teamspeak '''
 | 
					    ''' For Teamspeak '''
 | 
				
			||||||
@ -123,12 +140,10 @@ def utility_processor():
 | 
				
			|||||||
                img.write(i)
 | 
					                img.write(i)
 | 
				
			||||||
        return img_file
 | 
					        return img_file
 | 
				
			||||||
    ''' Misc '''
 | 
					    ''' Misc '''
 | 
				
			||||||
    def timestamp_to_js_date(timestamp):
 | 
					    def get_latest_news(num=3):
 | 
				
			||||||
        return strftime('%B %d, %Y %H:%M:%S UTC', gmtime(timestamp))
 | 
					        return latest_news(num)
 | 
				
			||||||
    def js_date_to_timestamp(date):
 | 
					 | 
				
			||||||
        return timegm(strptime(date, '%s, %d %b %Y %H:%M:%S %Z'))
 | 
					 | 
				
			||||||
    return dict(ts3_viewer=ts3_viewer, ts3_current_clients=ts3_current_clients, get_teamspeak_window=get_teamspeak_window, \
 | 
					    return dict(ts3_viewer=ts3_viewer, ts3_current_clients=ts3_current_clients, get_teamspeak_window=get_teamspeak_window, \
 | 
				
			||||||
            ts3_active_clients=ts3_active_clients, timestamp_to_js_date=timestamp_to_js_date, js_date_to_timestamp=js_date_to_timestamp, \
 | 
					            ts3_active_clients=ts3_active_clients, \
 | 
				
			||||||
            num_unique_clients_by_country=num_unique_clients_by_country, country_abbreviation_mapping=country_abbreviation_mapping, \
 | 
					            num_unique_clients_by_country=num_unique_clients_by_country, country_abbreviation_mapping=country_abbreviation_mapping, \
 | 
				
			||||||
            ts3_countries_active=ts3_countries_active, hero_image_large=hero_image_large, hero_image_small=hero_image_small, \
 | 
					            ts3_countries_active=ts3_countries_active, hero_image_large=hero_image_large, hero_image_small=hero_image_small, \
 | 
				
			||||||
            heropedia=parse_valve_heropedia, total_hero_pool=total_hero_pool)
 | 
					            heropedia=parse_valve_heropedia, total_hero_pool=total_hero_pool, get_latest_news=get_latest_news)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										132
									
								
								views.py
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								views.py
									
									
									
									
									
								
							@ -1,11 +1,14 @@
 | 
				
			|||||||
from flask import render_template, flash, redirect, g, request, url_for, session
 | 
					from flask import render_template, flash, redirect, g, request, url_for, session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from datetime import datetime
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					from functools import wraps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from app import app, db, oid, cache
 | 
					from app import app, db, oid, cache
 | 
				
			||||||
from models import User
 | 
					from models import User, Event
 | 
				
			||||||
from utils import get_steam_userinfo
 | 
					from utils import get_steam_userinfo
 | 
				
			||||||
from board import latest_news
 | 
					from board import registerUserForumId
 | 
				
			||||||
from forms import SettingsForm
 | 
					from teamspeak import registerUserTeamspeakId
 | 
				
			||||||
 | 
					from forms import SettingsForm, EventForm, EnableStatsForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.before_request
 | 
					@app.before_request
 | 
				
			||||||
def before_request():
 | 
					def before_request():
 | 
				
			||||||
@ -16,9 +19,29 @@ def before_request():
 | 
				
			|||||||
                g.user.last_seen = datetime.utcnow()
 | 
					                g.user.last_seen = datetime.utcnow()
 | 
				
			||||||
                db.session.commit()
 | 
					                db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def login_required(f):
 | 
				
			||||||
 | 
					    @wraps(f)
 | 
				
			||||||
 | 
					    def decorated_function(*args, **kwargs):
 | 
				
			||||||
 | 
					        if g.user is None:
 | 
				
			||||||
 | 
					            return redirect(url_for('login', next=request.url))
 | 
				
			||||||
 | 
					        return f(*args, **kwargs)
 | 
				
			||||||
 | 
					    return decorated_function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def flash_form_errors(form):
 | 
				
			||||||
 | 
					    for field, errors in form.errors.items():
 | 
				
			||||||
 | 
					        for error in errors:
 | 
				
			||||||
 | 
					            flash(u"Error in the %s field - %s" % (getattr(form,field).label.text, error), 'danger')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Application routes
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route('/')
 | 
					@app.route('/')
 | 
				
			||||||
def index():
 | 
					def index():
 | 
				
			||||||
	return render_template("index.html", latest_news=latest_news())
 | 
					    active = Event.query.filter(Event.start_time <= datetime.utcnow(), Event.end_time > datetime.utcnow()).all()
 | 
				
			||||||
 | 
					    upcoming =  Event.query.filter(Event.start_time > datetime.utcnow()).limit(2).all()
 | 
				
			||||||
 | 
					    return render_template("index.html", active_events=active, upcoming_events=upcoming)
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@app.route('/login')
 | 
					@app.route('/login')
 | 
				
			||||||
@oid.loginhandler
 | 
					@oid.loginhandler
 | 
				
			||||||
@ -36,32 +59,20 @@ def create_or_login(resp):
 | 
				
			|||||||
	g.user.avatar = steamdata['avatar']
 | 
						g.user.avatar = steamdata['avatar']
 | 
				
			||||||
	db.session.commit()
 | 
						db.session.commit()
 | 
				
			||||||
	session['user_id'] = g.user.id
 | 
						session['user_id'] = g.user.id
 | 
				
			||||||
        flash("You are logged in as {}".format(g.user.nickname))
 | 
					        flash("You are logged in as {}".format(g.user.nickname), 'success')
 | 
				
			||||||
	return redirect(oid.get_next_url())
 | 
						return redirect(oid.get_next_url())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route('/logout')
 | 
					@app.route('/logout')
 | 
				
			||||||
def logout():
 | 
					def logout():
 | 
				
			||||||
	session.pop('user_id', None)
 | 
						session.pop('user_id', None)
 | 
				
			||||||
	return redirect(oid.get_next_url())
 | 
					        g.user = None
 | 
				
			||||||
 | 
					        flash("You have been logged out.", 'success')
 | 
				
			||||||
 | 
						return redirect(url_for('index'))
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
					 | 
				
			||||||
### TEMPORARY ###
 | 
					 | 
				
			||||||
@app.route('/list_events')
 | 
					 | 
				
			||||||
def list_events():
 | 
					 | 
				
			||||||
	return "Events list!"
 | 
					 | 
				
			||||||
@app.route('/community')
 | 
					 | 
				
			||||||
def community():
 | 
					 | 
				
			||||||
	return "Community!"
 | 
					 | 
				
			||||||
@app.route('/ladder')
 | 
					 | 
				
			||||||
def ladder():
 | 
					 | 
				
			||||||
	return "Ladder!"
 | 
					 | 
				
			||||||
### ###
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Teamspeak statistics page
 | 
					# Teamspeak statistics page
 | 
				
			||||||
@app.route('/teamspeak')
 | 
					@app.route('/teamspeak')
 | 
				
			||||||
def teamspeak():
 | 
					def teamspeak():
 | 
				
			||||||
        return render_template('teamspeak.html')
 | 
					    return render_template('teamspeak.html')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Friends of doobs page
 | 
					# Friends of doobs page
 | 
				
			||||||
@app.route('/friends')
 | 
					@app.route('/friends')
 | 
				
			||||||
@ -87,15 +98,80 @@ def user_random_hero(userid):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# User settings page
 | 
					# User settings page
 | 
				
			||||||
@app.route('/settings', methods=['POST', 'GET'])
 | 
					@app.route('/settings', methods=['POST', 'GET'])
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
def user_settings():
 | 
					def user_settings():
 | 
				
			||||||
    user = User.query.filter_by(id=g.user.id).first_or_404()
 | 
					    user = User.query.filter_by(id=g.user.id).first_or_404()
 | 
				
			||||||
    form = SettingsForm(obj=user)
 | 
					    form = SettingsForm(obj=user)
 | 
				
			||||||
    if form.validate_on_submit():
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
        g.user.bio_text = form.bio_text.data
 | 
					 | 
				
			||||||
        g.user.twitch = form.twitch.data
 | 
					 | 
				
			||||||
        db.session.commit()
 | 
					 | 
				
			||||||
        flash('Settings updated!')
 | 
					 | 
				
			||||||
        return render_template('profile.html', user=g.user)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        form.populate_obj(user)
 | 
					        form.populate_obj(user)
 | 
				
			||||||
    return render_template('settings.html', user=g.user, form=form)
 | 
					        if user.bio_text == '':
 | 
				
			||||||
 | 
					            user.bio_text = None
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					        flash('Settings updated!', 'success')
 | 
				
			||||||
 | 
					    return render_template('settings.html', form=form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Enable user statistics page
 | 
				
			||||||
 | 
					@app.route('/settings/enable_stats', methods=['POST', 'GET'])
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def enable_statistics():
 | 
				
			||||||
 | 
					    # TODO: update user_settings to use g.user, avoid extra queries
 | 
				
			||||||
 | 
					    form = EnableStatsForm(obj=g.user)
 | 
				
			||||||
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
 | 
					        forum_data = registerUserForumId(g.user, form.forum_username.data, form.forum_password.data)
 | 
				
			||||||
 | 
					        if forum_data:
 | 
				
			||||||
 | 
					            flash('Forum account \''+forum_data['forum_name']+'\' linked!', 'success')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            flash('Forum account credentials invalid', 'danger')
 | 
				
			||||||
 | 
					        if registerUserTeamspeakId(g.user, form.teamspeak_id.data):
 | 
				
			||||||
 | 
					            flash('Teamspeak account linked successfully!', 'success')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            flash('Teamspeak ID not found in client history', 'danger')
 | 
				
			||||||
 | 
					    return render_template('enable_stats.html', form=form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Events list
 | 
				
			||||||
 | 
					@app.route('/events', methods=['GET'])
 | 
				
			||||||
 | 
					def list_events():
 | 
				
			||||||
 | 
					    now = datetime.utcnow()
 | 
				
			||||||
 | 
					    active = Event.query.filter(Event.start_time <= now, Event.end_time > now).all()
 | 
				
			||||||
 | 
					    upcoming = Event.query.filter(Event.start_time > now).all()
 | 
				
			||||||
 | 
					    expired = Event.query.filter(Event.end_time < now).all()
 | 
				
			||||||
 | 
					    return render_template('list_events.html', active=active, upcoming=upcoming, expired=expired)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Show event info
 | 
				
			||||||
 | 
					@app.route('/event/<int:eventid>', methods=['GET'])
 | 
				
			||||||
 | 
					def show_event(eventid):
 | 
				
			||||||
 | 
					    event = Event.query.filter_by(id=eventid).first_or_404()
 | 
				
			||||||
 | 
					    return render_template('show_event.html', event=event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Event creation page
 | 
				
			||||||
 | 
					@app.route('/event/edit', methods=['POST', 'GET'])
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def event_edit():
 | 
				
			||||||
 | 
					    if not g.user.admin:
 | 
				
			||||||
 | 
					        flash('Access Denied: You cannot create/edit events.', 'danger')
 | 
				
			||||||
 | 
					        return redirect(url_for('index'))
 | 
				
			||||||
 | 
					    eventid = request.args.get('eventid')
 | 
				
			||||||
 | 
					    event = Event.get_or_create(eventid)
 | 
				
			||||||
 | 
					    form = EventForm(obj=event)
 | 
				
			||||||
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
 | 
					        form.populate_obj(event)
 | 
				
			||||||
 | 
					        db.session.add(event)
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					        flash('New event created!', 'success') if eventid is None else flash('Event updated successfully!', 'success')
 | 
				
			||||||
 | 
					        return redirect(url_for('show_event', eventid=event.id))
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        flash_form_errors(form)
 | 
				
			||||||
 | 
					    return render_template('edit_event.html', event=event, form=form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Event deletion call
 | 
				
			||||||
 | 
					@app.route('/event/<int:eventid>/delete', methods=['GET'])
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def event_delete(eventid):
 | 
				
			||||||
 | 
					    if g.user.admin:
 | 
				
			||||||
 | 
					        event = Event.query.filter_by(id=eventid).first_or_404()
 | 
				
			||||||
 | 
					        flash('Info: Event "{}" deleted successfully.'.format(event.name), 'success')
 | 
				
			||||||
 | 
					        db.session.delete(event)
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        flash('Access Denied: You cannot delete events.', 'danger')
 | 
				
			||||||
 | 
					    return redirect(url_for('index'))
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user