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