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)
 | 
			
		||||
cache = Cache(app, config={'CACHE_TYPE': app.config['CACHE_TYPE']})
 | 
			
		||||
 | 
			
		||||
from app import views
 | 
			
		||||
 | 
			
		||||
'''
 | 
			
		||||
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)
 | 
			
		||||
			
 | 
			
		||||
			
 | 
			
		||||
			'''
 | 
			
		||||
from app import views, models
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								board.py
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								board.py
									
									
									
									
									
								
							@ -1,17 +1,31 @@
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
from time import strftime, gmtime
 | 
			
		||||
from hashlib import sha256
 | 
			
		||||
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']})
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
def latest_news(num=3):
 | 
			
		||||
	latest_news = []
 | 
			
		||||
        try:
 | 
			
		||||
		db.connect()
 | 
			
		||||
		board_db.connect()
 | 
			
		||||
		news_forum = Forums.get(fn.Lower(Forums.title) % '%news%')
 | 
			
		||||
		for thread in Threads.select().where(
 | 
			
		||||
			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:
 | 
			
		||||
		latest_news.append({'title':'Error with forum db', 'text':e, 'url':''})
 | 
			
		||||
        finally:
 | 
			
		||||
		db.close()
 | 
			
		||||
		board_db.close()
 | 
			
		||||
	return latest_news
 | 
			
		||||
					
 | 
			
		||||
class UnknownFieldType(object):
 | 
			
		||||
@ -40,7 +54,7 @@ class UnknownFieldType(object):
 | 
			
		||||
 | 
			
		||||
class BaseModel(Model):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        database = db
 | 
			
		||||
        database = board_db
 | 
			
		||||
 | 
			
		||||
class Badges(BaseModel):
 | 
			
		||||
    color = IntegerField()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								forms.py
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								forms.py
									
									
									
									
									
								
							@ -1,7 +1,23 @@
 | 
			
		||||
from flask.ext.wtf import Form
 | 
			
		||||
from wtforms import TextField, BooleanField, TextAreaField
 | 
			
		||||
from flask_wtf import Form
 | 
			
		||||
from wtforms import TextField, BooleanField, TextAreaField, PasswordField, SelectField, IntegerField, DateTimeField, validators
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
class SettingsForm(Form):
 | 
			
		||||
    public = BooleanField('public', default=True)
 | 
			
		||||
    logo = BooleanField('biglogo', default=True)
 | 
			
		||||
    twitch = TextField('twitch')
 | 
			
		||||
    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')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										219
									
								
								models.py
									
									
									
									
									
								
							
							
						
						
									
										219
									
								
								models.py
									
									
									
									
									
								
							@ -1,11 +1,23 @@
 | 
			
		||||
import simplejson as json
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from random import choice
 | 
			
		||||
from flask.ext.sqlalchemy import SQLAlchemy
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
class Json(db.TypeDecorator):
 | 
			
		||||
    impl = db.Text
 | 
			
		||||
@ -20,7 +32,7 @@ class Json(db.TypeDecorator):
 | 
			
		||||
            value = json.loads(value)
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Mongoness factor - phase 2
 | 
			
		||||
class MutableDict(Mutable, dict):
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def coerce(cls, key, value):
 | 
			
		||||
@ -46,27 +58,51 @@ class MutableDict(Mutable, dict):
 | 
			
		||||
        self.update(self)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class User(db.Model):
 | 
			
		||||
	id = db.Column(db.Integer, primary_key=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))
 | 
			
		||||
	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))
 | 
			
		||||
        created = db.Column(db.DateTime)
 | 
			
		||||
        last_seen = db.Column(db.DateTime)
 | 
			
		||||
        twitch = db.Column(db.String(60))
 | 
			
		||||
        random_heroes = db.Column(MutableDict.as_mutable(Json))
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def get_or_create(steam_id):
 | 
			
		||||
            rv = User.query.filter_by(steam_id=steam_id).first()
 | 
			
		||||
            if rv is None:
 | 
			
		||||
                rv = User()
 | 
			
		||||
                rv.steam_id = steam_id
 | 
			
		||||
                rv.random_heroes = {'current':None, 'completed':[]}
 | 
			
		||||
                bio_text = ''
 | 
			
		||||
                db.session.add(rv)
 | 
			
		||||
            return rv
 | 
			
		||||
        public = db.Column(db.Boolean)
 | 
			
		||||
        logo = db.Column(db.Boolean)
 | 
			
		||||
 | 
			
		||||
        points_from_events = db.Column(db.Integer)
 | 
			
		||||
        points_from_ts3 = db.Column(db.Integer)
 | 
			
		||||
        points_from_forum = db.Column(db.Integer)
 | 
			
		||||
        ts3_starttime = db.Column(db.DateTime)
 | 
			
		||||
        ts3_endtime = db.Column(db.DateTime)
 | 
			
		||||
        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
 | 
			
		||||
        def random_hero(self):
 | 
			
		||||
@ -103,14 +139,161 @@ class User(db.Model):
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
            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):
 | 
			
		||||
            return '<User {}>'.format(self.nickname)
 | 
			
		||||
            return '<User {}>'.format(self.id)
 | 
			
		||||
 | 
			
		||||
class TeamspeakData(db.Model):
 | 
			
		||||
        id = db.Column(db.Integer, primary_key=True)
 | 
			
		||||
        time = db.Column(db.Float())
 | 
			
		||||
        time = db.Column(db.DateTime())
 | 
			
		||||
        clients = db.Column(Json())
 | 
			
		||||
 | 
			
		||||
        def __init__(self, clientlist):
 | 
			
		||||
            self.time = time()
 | 
			
		||||
            self.time = datetime.utcnow() 
 | 
			
		||||
            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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#streams-online > .uk-article > a > h4 {
 | 
			
		||||
    margin:0px;
 | 
			
		||||
}
 | 
			
		||||
#tsviewer > .uk-modal-dialog {
 | 
			
		||||
    max-height: 80%;
 | 
			
		||||
    overflow-y: scroll;
 | 
			
		||||
@ -63,16 +60,21 @@ footer {
 | 
			
		||||
}
 | 
			
		||||
.dn-streamer, .dn-streamer-offline {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    width: 110px;
 | 
			
		||||
    padding: 5px;
 | 
			
		||||
    margin: 5px;
 | 
			
		||||
    width: 105px;
 | 
			
		||||
    padding: 2px;
 | 
			
		||||
    margin: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#streams p.uk-text-bold {
 | 
			
		||||
    font-size: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dn-streamer-offline > img {
 | 
			
		||||
    height:50px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dn-streamer-hover {
 | 
			
		||||
    background:red;
 | 
			
		||||
    background:#CACACA;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dn-hero-icon {
 | 
			
		||||
@ -80,3 +82,19 @@ footer {
 | 
			
		||||
    padding:4px;
 | 
			
		||||
    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 os
 | 
			
		||||
import ts3
 | 
			
		||||
import time
 | 
			
		||||
import requests
 | 
			
		||||
from datetime import datetime, timedelta
 | 
			
		||||
from xml.etree import ElementTree
 | 
			
		||||
from flask import url_for
 | 
			
		||||
from bs4 import BeautifulSoup
 | 
			
		||||
 | 
			
		||||
from app import app
 | 
			
		||||
from app import app, db
 | 
			
		||||
 | 
			
		||||
def getTeamspeakWindow(window=605800):
 | 
			
		||||
    current_time = time.time()
 | 
			
		||||
def getTeamspeakWindow(window=timedelta(weeks=1)):
 | 
			
		||||
    current_time = datetime.utcnow()
 | 
			
		||||
    from models import TeamspeakData
 | 
			
		||||
    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():
 | 
			
		||||
    try:
 | 
			
		||||
            server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="uk-width-large-1-2 uk-width-medium-1-1 uk-text-center uk-panel botpad">
 | 
			
		||||
        <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>
 | 
			
		||||
            <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>
 | 
			
		||||
@ -26,10 +26,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="uk-width-large-1-2 uk-width-medium-1-1 uk-text-center uk-panel">
 | 
			
		||||
        <h2>Streams We Like</h2>
 | 
			
		||||
        <ul id="streams-online">
 | 
			
		||||
        </ul>
 | 
			
		||||
        <hr id="stream-divider" class="uk-article-divider" style="display:none;" />
 | 
			
		||||
        <ul id="streams-offline">
 | 
			
		||||
        <ul id="streams">
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
@ -38,34 +35,49 @@
 | 
			
		||||
{% block pagescripts %}
 | 
			
		||||
<script>
 | 
			
		||||
$(document).ready(function() {
 | 
			
		||||
        {% cache 60*5 %}
 | 
			
		||||
	// Add the 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) {
 | 
			
		||||
		$.getJSON(stream_url+channels[idx]+"?callback=?", function(data) {
 | 
			
		||||
			if (data.stream) {
 | 
			
		||||
				$('#streams-online').append("<article class='uk-article' id='" + data.stream.channel.name + "'>");
 | 
			
		||||
				var jquery_selector = '#'+data.stream.channel.name;
 | 
			
		||||
                                $(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'>";
 | 
			
		||||
				span_text = span_text + "Playing: " + data.stream.game  + "<br />";
 | 
			
		||||
				span_text = span_text + "Viewers: " + data.stream.viewers + "<br />";
 | 
			
		||||
				span_text = span_text + "</p>";
 | 
			
		||||
				$(jquery_selector).append(span_text);
 | 
			
		||||
				$(jquery_selector).append("<img src='" + data.stream.preview.medium + "' class='' />")
 | 
			
		||||
				$('#streams-online').append("</article>");
 | 
			
		||||
                                $('#stream-divider').show();
 | 
			
		||||
			} else {
 | 
			
		||||
				$.getJSON(data._links.channel+"?callback=?", function(data) {
 | 
			
		||||
					$('#streams-offline').append("<article class='uk-article' id='" + data.name + "'>");
 | 
			
		||||
                                        $('#'+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 />");
 | 
			
		||||
					$('#'+data.name).append("<p class='uk-article-meta'><strong>Offline</strong></p>");
 | 
			
		||||
					$('#streams-offline').append("</div>");
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
                    if (data.stream) {
 | 
			
		||||
                        var $a = $("<a href='"+data.stream.channel.url+"'></a>");
 | 
			
		||||
                        var $strm = $("<div class='dn-streamer uk-text-success uk-panel uk-panel-box' id='"+data.stream.channel.name+"'></div>");
 | 
			
		||||
 | 
			
		||||
                        $strm.append("<p class='uk-text-bold'>" + data.stream.channel.display_name + "</p>");
 | 
			
		||||
                        $strm.append("<img src='" + data.stream.preview.small + "' />");
 | 
			
		||||
                        $strm.append("<p><i class='uk-icon-male'></i> "+data.stream.viewers+"</p>");
 | 
			
		||||
 | 
			
		||||
                        $a.append($strm);
 | 
			
		||||
                        $("#streams").prepend($a);
 | 
			
		||||
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $.getJSON(data._links.channel+"?callback=?", function(data) {
 | 
			
		||||
                            var $a = $("<a href='"+data.url+"'></a>");
 | 
			
		||||
                            var $strm = $("<div class='dn-streamer-offline uk-text-success uk-panel uk-panel-box' id='"+data.name+"'></div>");
 | 
			
		||||
 | 
			
		||||
                            $strm.append("<p class='uk-text-bold'>" + data.display_name + "</p>");
 | 
			
		||||
                            $strm.append("<img src='" + data.logo + "' />");
 | 
			
		||||
                            $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>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
@ -5,32 +5,16 @@
 | 
			
		||||
{% block title %}Dota Noobs{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{#{% cache 60*5 %}#}
 | 
			
		||||
{% cache 60*5 %}
 | 
			
		||||
{% set teamspeak_data = get_teamspeak_window() %}
 | 
			
		||||
{% set latest_news = get_latest_news() %}
 | 
			
		||||
<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>
 | 
			
		||||
        {#
 | 
			
		||||
        {% 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 id="events_large" class="uk-width-1-2 uk-visible-large uk-panel uk-panel-space">
 | 
			
		||||
        {% include "events_widget.html" %}
 | 
			
		||||
    </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>
 | 
			
		||||
        <h1 class="uk-panel-title">Teamspeak</h1>
 | 
			
		||||
        <div class="uk-grid uk-margin-bottom">
 | 
			
		||||
@ -57,11 +41,15 @@
 | 
			
		||||
        </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 class="uk-width-1-1 uk-panel uk-panel-header">
 | 
			
		||||
        <h4 class="uk-panel-title">News and Announcements</h4>
 | 
			
		||||
    <div id="streams" class="uk-width-1-1 uk-text-center uk-panel">
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="uk-width-1-1 uk-panel uk-panel-header uk-panel-space">
 | 
			
		||||
        <h1 class="uk-panel-title">News and Announcements</h1>
 | 
			
		||||
        {% for news in latest_news %}
 | 
			
		||||
            <article class="uk-article dn-news-article">
 | 
			
		||||
            <h4 class="uk-article-title" title="{{ news['title'] }}"><a href="{{ news['url'] }}">{{ news['title'] }}</a></h4>
 | 
			
		||||
@ -70,15 +58,22 @@
 | 
			
		||||
            </article>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{#{% endcache %}#}
 | 
			
		||||
{% endcache %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block pagescripts %}
 | 
			
		||||
<script>
 | 
			
		||||
{% cache 60*5 %}
 | 
			
		||||
$(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
 | 
			
		||||
	var stream_url = "https://api.twitch.tv/kraken/streams/";
 | 
			
		||||
        var channels = ["dotanoobs", "bearhugdota", "kreejaffakree", "prettypenguins", "shaneomad"];
 | 
			
		||||
@ -113,7 +108,7 @@ $(document).ready(function() {
 | 
			
		||||
        {% endcache %}
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        $(".dn-streamer, .dn-streamer-offline").on({
 | 
			
		||||
        $("#streams").on({
 | 
			
		||||
            mouseover: function() {
 | 
			
		||||
                $(this).addClass('dn-streamer-hover');
 | 
			
		||||
            },
 | 
			
		||||
@ -121,12 +116,6 @@ $(document).ready(function() {
 | 
			
		||||
                $(this).removeClass('dn-streamer-hover');
 | 
			
		||||
            }
 | 
			
		||||
        }, "div");
 | 
			
		||||
 | 
			
		||||
        // Localize the events
 | 
			
		||||
	$('.date').each( function( index ) {
 | 
			
		||||
		var d = new Date($(this).text());
 | 
			
		||||
		$(this).text( d.toLocaleDateString() + ' @ ' + d.toLocaleTimeString() );
 | 
			
		||||
        });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
@ -10,13 +10,14 @@
 | 
			
		||||
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
			
		||||
 | 
			
		||||
        <!-- CSS includes -->
 | 
			
		||||
        <!--<link rel="stylesheet" href="{{ url_for('static', filename='css/uikit.min.css') }}" />-->
 | 
			
		||||
        <link rel="stylesheet" href="{{ url_for('static', filename='css/uikit.gradient.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/app.css') }}" />
 | 
			
		||||
 | 
			
		||||
        <!-- Javascript includes -->
 | 
			
		||||
        <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>
 | 
			
		||||
    <body>
 | 
			
		||||
        <!-- 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_random_hero', userid=g.user.id) }}">A-Z Challenge</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><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>
 | 
			
		||||
                </ul>
 | 
			
		||||
           </div>
 | 
			
		||||
        </ul>
 | 
			
		||||
        {% 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 %}
 | 
			
		||||
        <div class="uk-navbar-content uk-navbar-center uk-hidden-small uk-text-bold">DotaNoobs</div>
 | 
			
		||||
        </nav>
 | 
			
		||||
 | 
			
		||||
        <!-- Flash Error Messages -->
 | 
			
		||||
        {% with messages = get_flashed_messages() %}
 | 
			
		||||
        {% with messages = get_flashed_messages(with_categories=true) %}
 | 
			
		||||
        {% if messages %}
 | 
			
		||||
        <ul class="flashes uk-width-1-3 uk-container-center">
 | 
			
		||||
            <a href="" class="uk-alert-close uk-close"></a>
 | 
			
		||||
            {% for message in messages %}
 | 
			
		||||
            <li class="uk-alert uk-alert-danger">{{ message }}</li>
 | 
			
		||||
        <ul class="uk-list flashes uk-width-2-3  uk-container-center">
 | 
			
		||||
            {% for category, message in messages %}
 | 
			
		||||
            <li class="uk-alert uk-alert-{{ category }}">{{ message }} <a href="#" class="uk-alert-close uk-close"></a> </li>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </ul>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
@ -60,7 +63,9 @@
 | 
			
		||||
        <!-- Start Main Container -->
 | 
			
		||||
        <div id="container" class="uk-grid">
 | 
			
		||||
            <!-- 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>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            <!-- Side navigation -->
 | 
			
		||||
            <div class="uk-visible-large uk-width-1-5 uk-panel">
 | 
			
		||||
                {% if g.doob%}
 | 
			
		||||
@ -78,9 +83,10 @@
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    <ul class="uk-nav uk-nav-offcanvas" data-uk-nav>
 | 
			
		||||
                        {% include 'sidenav.html' %}
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <!-- Main content area -->
 | 
			
		||||
            <div class="uk-width-large-4-5 uk-width-medium-5-5">
 | 
			
		||||
                {% block content %}
 | 
			
		||||
@ -91,6 +97,7 @@
 | 
			
		||||
 | 
			
		||||
        <!-- Footer section -->
 | 
			
		||||
        <footer class="uk-clearfix uk-align-center">
 | 
			
		||||
        {% cache 60*5 %}
 | 
			
		||||
        <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://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="emailto:admin@dotanoobs.com"><img src="{{ url_for('static', filename='img/email.png') }}" /></a>
 | 
			
		||||
        </div>
 | 
			
		||||
        {% endcache %}
 | 
			
		||||
        </footer>
 | 
			
		||||
        <!-- Page-specific javascript here -->
 | 
			
		||||
        {% block pagescripts %}
 | 
			
		||||
        {% 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>
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,22 +7,31 @@
 | 
			
		||||
    <div class="uk-width-2-3">
 | 
			
		||||
        <h2 class="uk-float-left"><img class="" src="{{ user.avatar }}" /> {{ user.nickname }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="uk-width-1-3 uk-text-center">
 | 
			
		||||
        <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>
 | 
			
		||||
    <div id="profile_links" class="uk-width-1-3 uk-text-center">
 | 
			
		||||
        <div class="uk-panel">
 | 
			
		||||
            {% if user.public %}
 | 
			
		||||
            <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>
 | 
			
		||||
    <!--Main content area -->
 | 
			
		||||
    <div class="uk-width-large-2-3 uk-width-medium-1-1 uk-panel">
 | 
			
		||||
    {% if user.public %}
 | 
			
		||||
        {% if user.bio_text == None %}
 | 
			
		||||
        <em class="uk-text-danger">This user's profile bio is empty!</em>
 | 
			
		||||
        {% else %}
 | 
			
		||||
        <em class="uk-text-bold">{{ user.bio_text }}</em>
 | 
			
		||||
        {% 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 %}
 | 
			
		||||
    </div> 
 | 
			
		||||
    <!-- Side bar -->
 | 
			
		||||
    <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">
 | 
			
		||||
            <span class="uk-text-bold">Current Hero</span><br/>
 | 
			
		||||
            <span>{{ user.random_hero['localized_name'] }}</span><br/>
 | 
			
		||||
@ -31,11 +40,13 @@
 | 
			
		||||
                <span>View A-Z Progress</span>
 | 
			
		||||
            </a>
 | 
			
		||||
        </div>
 | 
			
		||||
        <ul class="uk-list uk-list-space uk-list-striped">
 | 
			
		||||
            <li>Points: <span id='points_total'>0</span></li>
 | 
			
		||||
            <li>Last Seen: <span id='date'></span></li>
 | 
			
		||||
            <li>Heroes Randomed: <span id='rands'>{{ user.random_heroes.completed | length }}</span></li>
 | 
			
		||||
        <ul class="uk-list uk-list-space uk-list-striped uk-text-center uk-text-small">
 | 
			
		||||
            <li>Completed <span id='rands'>{{ user.random_heroes.completed | length }}</span> heroes in A-Z</li>
 | 
			
		||||
            <li>Has <span id='points_total'>0</span> doobs points</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>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
@ -5,21 +5,20 @@
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="uk-grid" data-uk-grid-margin>
 | 
			
		||||
    <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 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>
 | 
			
		||||
    <!--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.hidden_tag() }}
 | 
			
		||||
            <fieldset data-uk-margin>
 | 
			
		||||
                <legend>Settings</legend>
 | 
			
		||||
                <div class="uk-form-row">
 | 
			
		||||
                    <ul class="uk-list">
 | 
			
		||||
                        <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"><input type="checkbox" disabled> Nonexistant Setting</label></li>
 | 
			
		||||
                        <li><label class="uk-form-label"> {{ form.logo }} Hide Big Logo</label></li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="uk-form-row">
 | 
			
		||||
 | 
			
		||||
@ -17,15 +17,16 @@
 | 
			
		||||
    </li>
 | 
			
		||||
    <li class="uk-nav-divider"></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://www.youtube.com/user/DotaNoobsVods"><i class="uk-icon-youtube"> YouTube</i></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://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"></i> YouTube</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-header">Controls</li>
 | 
			
		||||
    {% 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-cog"> Register</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-star"></i> Register</a></li>
 | 
			
		||||
    {% 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><a href="{{ url_for('user_settings', userid=g.user.id) }}"><i class="uk-icon-cog"> Settings</i></a></li>
 | 
			
		||||
    <li><a href="{{ url_for('logout') }}"><i class="uk-icon-off"> Logout</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 {% 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-sign-out"></i> Logout</a></li>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
@ -13,9 +13,9 @@
 | 
			
		||||
        <h3 class="uk-text-bold uk-text-center">Recent Activity</h3>
 | 
			
		||||
        <div class="uk-panel">
 | 
			
		||||
            <ul>
 | 
			
		||||
                <li>Active users connected: <span id="unique_clients"></span></li>
 | 
			
		||||
                <li>Total users connected:  <span id="current_clients">{{ ts3_current_clients() }}</span></li>
 | 
			
		||||
                <li>Countries active on server: <span id="country_clients"></span></li>
 | 
			
		||||
                <li>Users currently connected:  <span id="current_clients"></span></li>
 | 
			
		||||
                <li>Unique users this week: <span id="unique_clients"></span></li>
 | 
			
		||||
                <li>Countries active this week: <span id="country_clients"></span></li>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="uk-panel" id="teamspeak_active_users"></div>
 | 
			
		||||
        <div class="uk-panel" id="teamspeak_map"></div>
 | 
			
		||||
@ -38,13 +38,14 @@
 | 
			
		||||
{% block pagescripts %}
 | 
			
		||||
{% cache 60*5 %}
 | 
			
		||||
{% set teamspeak_data = get_teamspeak_window() %}
 | 
			
		||||
<script src="http://code.highcharts.com/3.0.1/highcharts.js"></script>
 | 
			
		||||
<script type="text/javascript" src="http://github.highcharts.com/75c66eb3/modules/map.src.js"></script>
 | 
			
		||||
<script type="text/javascript" src="http://github.highcharts.com/75c66eb3/modules/data.src.js"></script>
 | 
			
		||||
<script src="//cdnjs.cloudflare.com/ajax/libs/highcharts/3.0.7/highcharts.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="//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>
 | 
			
		||||
$(document).ready(function() {
 | 
			
		||||
	$('#unique_clients').html("{{ ts3_active_clients(teamspeak_data) }}");
 | 
			
		||||
	$('#current_clients').html("{{ ts3_current_clients() }}");
 | 
			
		||||
	$('#country_clients').html("{{ ts3_countries_active(teamspeak_data) }}");
 | 
			
		||||
	Highcharts.setOptions({
 | 
			
		||||
		global: {
 | 
			
		||||
@ -90,7 +91,7 @@ $(document).ready(function() {
 | 
			
		||||
			type: 'areaspline',
 | 
			
		||||
			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 %}
 | 
			
		||||
			],
 | 
			
		||||
		}],
 | 
			
		||||
@ -155,7 +156,7 @@ $(document).ready(function() {
 | 
			
		||||
		map_options.series[0].data.push({
 | 
			
		||||
			y: num,
 | 
			
		||||
			name: country_names[key],
 | 
			
		||||
			path: Highcharts.pathToArray(shapes[key]),
 | 
			
		||||
			path: shapes[key],
 | 
			
		||||
			states: {
 | 
			
		||||
				hover: {
 | 
			
		||||
					color: '#FF7F00'
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								utils.py
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								utils.py
									
									
									
									
									
								
							@ -7,6 +7,7 @@ from os import path, makedirs
 | 
			
		||||
 | 
			
		||||
from calendar import timegm
 | 
			
		||||
from app import app, cache
 | 
			
		||||
from board import latest_news
 | 
			
		||||
from teamspeak import create_teamspeak_viewer, getTeamspeakWindow, ISO3166_MAPPING
 | 
			
		||||
 | 
			
		||||
def get_steam_userinfo(steam_id):
 | 
			
		||||
@ -55,6 +56,22 @@ def shorten_filter(s, num_words=40):
 | 
			
		||||
		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
 | 
			
		||||
def utility_processor():
 | 
			
		||||
    ''' For Teamspeak '''
 | 
			
		||||
@ -123,12 +140,10 @@ def utility_processor():
 | 
			
		||||
                img.write(i)
 | 
			
		||||
        return img_file
 | 
			
		||||
    ''' Misc '''
 | 
			
		||||
    def timestamp_to_js_date(timestamp):
 | 
			
		||||
        return strftime('%B %d, %Y %H:%M:%S UTC', gmtime(timestamp))
 | 
			
		||||
    def js_date_to_timestamp(date):
 | 
			
		||||
        return timegm(strptime(date, '%s, %d %b %Y %H:%M:%S %Z'))
 | 
			
		||||
    def get_latest_news(num=3):
 | 
			
		||||
        return latest_news(num)
 | 
			
		||||
    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, \
 | 
			
		||||
            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 datetime import datetime
 | 
			
		||||
from functools import wraps
 | 
			
		||||
 | 
			
		||||
from app import app, db, oid, cache
 | 
			
		||||
from models import User
 | 
			
		||||
from models import User, Event
 | 
			
		||||
from utils import get_steam_userinfo
 | 
			
		||||
from board import latest_news
 | 
			
		||||
from forms import SettingsForm
 | 
			
		||||
from board import registerUserForumId
 | 
			
		||||
from teamspeak import registerUserTeamspeakId
 | 
			
		||||
from forms import SettingsForm, EventForm, EnableStatsForm
 | 
			
		||||
 | 
			
		||||
@app.before_request
 | 
			
		||||
def before_request():
 | 
			
		||||
@ -16,9 +19,29 @@ def before_request():
 | 
			
		||||
                g.user.last_seen = datetime.utcnow()
 | 
			
		||||
                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('/')
 | 
			
		||||
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')
 | 
			
		||||
@oid.loginhandler
 | 
			
		||||
@ -36,32 +59,20 @@ def create_or_login(resp):
 | 
			
		||||
	g.user.avatar = steamdata['avatar']
 | 
			
		||||
	db.session.commit()
 | 
			
		||||
	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())
 | 
			
		||||
 | 
			
		||||
@app.route('/logout')
 | 
			
		||||
def logout():
 | 
			
		||||
	session.pop('user_id', None)
 | 
			
		||||
	return redirect(oid.get_next_url())
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
### 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!"
 | 
			
		||||
### ###
 | 
			
		||||
 | 
			
		||||
        g.user = None
 | 
			
		||||
        flash("You have been logged out.", 'success')
 | 
			
		||||
	return redirect(url_for('index'))
 | 
			
		||||
	
 | 
			
		||||
# Teamspeak statistics page
 | 
			
		||||
@app.route('/teamspeak')
 | 
			
		||||
def teamspeak():
 | 
			
		||||
        return render_template('teamspeak.html')
 | 
			
		||||
    return render_template('teamspeak.html')
 | 
			
		||||
 | 
			
		||||
# Friends of doobs page
 | 
			
		||||
@app.route('/friends')
 | 
			
		||||
@ -87,15 +98,80 @@ def user_random_hero(userid):
 | 
			
		||||
 | 
			
		||||
# User settings page
 | 
			
		||||
@app.route('/settings', methods=['POST', 'GET'])
 | 
			
		||||
@login_required
 | 
			
		||||
def user_settings():
 | 
			
		||||
    user = User.query.filter_by(id=g.user.id).first_or_404()
 | 
			
		||||
    form = SettingsForm(obj=user)
 | 
			
		||||
    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)
 | 
			
		||||
    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