Fixed MutableDict. Redesigned profile,random,settings. Added user bios
This commit is contained in:
parent
bc52fc0660
commit
23e04edafd
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,4 +3,4 @@ __pycache__/
|
|||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
|
||||||
*.so
|
*.so
|
||||||
|
static/img/hero-images/*.png
|
||||||
|
@ -227,4 +227,4 @@ def utility_processor():
|
|||||||
country_abbreviation_mapping=country_abbreviation_mapping)
|
country_abbreviation_mapping=country_abbreviation_mapping)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
7
forms.py
Normal file
7
forms.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from flask.ext.wtf import Form
|
||||||
|
from wtforms import TextField, BooleanField, TextAreaField
|
||||||
|
|
||||||
|
class SettingsForm(Form):
|
||||||
|
public = BooleanField('public', default=True)
|
||||||
|
twitch = TextField('twitch')
|
||||||
|
bio_text = TextAreaField('bio_text')
|
99
models.py
99
models.py
@ -1,35 +1,110 @@
|
|||||||
import simplejson as json
|
import simplejson as json
|
||||||
|
from random import choice
|
||||||
from flask.ext.sqlalchemy import SQLAlchemy
|
from flask.ext.sqlalchemy import SQLAlchemy
|
||||||
|
from sqlalchemy.ext.mutable import Mutable
|
||||||
from time import time
|
from time import time
|
||||||
from app import db
|
from app import db
|
||||||
|
from utils import parse_valve_heropedia, complete_hero_data
|
||||||
|
|
||||||
# Get a little of that Mongoness back
|
# Get a little of that Mongoness back
|
||||||
class Json(db.TypeDecorator):
|
class Json(db.TypeDecorator):
|
||||||
impl = db.Unicode
|
impl = db.Text
|
||||||
|
|
||||||
|
def process_bind_param(self, value, dialect):
|
||||||
|
if value is not None:
|
||||||
|
value = json.dumps(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def process_result_value(self, value, dialect):
|
||||||
|
if value is not None:
|
||||||
|
value = json.loads(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class MutableDict(Mutable, dict):
|
||||||
|
@classmethod
|
||||||
|
def coerce(cls, key, value):
|
||||||
|
if not isinstance(value, MutableDict):
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return MutableDict(value)
|
||||||
|
return Mutable.coerce(key,value)
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
dict.__delitem__(self, key)
|
||||||
|
self.changed()
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
dict.__setitem__(self, key, value)
|
||||||
|
self.changed()
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return dict(self)
|
||||||
|
|
||||||
|
def __setstate__(self, state):
|
||||||
|
self.update(self)
|
||||||
|
|
||||||
def process_bind_param(self, value, dialect):
|
|
||||||
return unicode(json.dumps(value))
|
|
||||||
|
|
||||||
def process_result_value(self, value, dialect):
|
|
||||||
return json.loads(value)
|
|
||||||
|
|
||||||
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)
|
||||||
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))
|
||||||
|
bio_text = db.Column(db.String(4096))
|
||||||
|
last_seen = db.Column(db.DateTime)
|
||||||
|
twitch = db.Column(db.String(60))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_or_create(steam_id):
|
def get_or_create(steam_id):
|
||||||
rv = User.query.filter_by(steam_id=steam_id).first()
|
rv = User.query.filter_by(steam_id=steam_id).first()
|
||||||
if rv is None:
|
if rv is None:
|
||||||
rv = User()
|
rv = User()
|
||||||
rv.steam_id = steam_id
|
rv.steam_id = steam_id
|
||||||
db.session.add(rv)
|
rv.random_heroes = {'current':None, 'completed':[]}
|
||||||
return rv
|
bio_text = ''
|
||||||
|
db.session.add(rv)
|
||||||
|
return rv
|
||||||
|
|
||||||
|
@property
|
||||||
|
def random_hero(self):
|
||||||
|
if not self.random_heroes['current']:
|
||||||
|
heroes = []
|
||||||
|
for (tavern_name, tavern) in parse_valve_heropedia():
|
||||||
|
heroes.extend([complete_hero_data('name', entry['name']) for entry in tavern])
|
||||||
|
if heroes:
|
||||||
|
self.random_heroes['current'] = choice(heroes)
|
||||||
|
self.random_heroes = self.random_heroes
|
||||||
|
db.session.commit()
|
||||||
|
return self.random_heroes['current']
|
||||||
|
|
||||||
|
@random_hero.setter
|
||||||
|
def random_hero(self, herodata):
|
||||||
|
self.random_heroes['current'] = herodata
|
||||||
|
self.random_heroes = self.random_heroes
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def random_completed(self):
|
||||||
|
return self.random_heroes['completed']
|
||||||
|
|
||||||
|
def random_success(self):
|
||||||
|
self.random_heroes['completed'].append(self.random_heroes['current']['name'])
|
||||||
|
self.random_heroes['current'] = None
|
||||||
|
self.random_heroes = self.random_heroes
|
||||||
|
db.session.commit()
|
||||||
|
return self.random_hero
|
||||||
|
|
||||||
|
def random_skip(self):
|
||||||
|
self.random_heroes['current'] = None
|
||||||
|
self.random_heroes = self.random_heroes
|
||||||
|
db.session.commit()
|
||||||
|
return self.random_hero
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<User {}>'.format(self.steam_id)
|
return '<User {}>'.format(self.nickname)
|
||||||
|
|
||||||
class TeamspeakData(db.Model):
|
class TeamspeakData(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
1250
static/country_codes.xml
Normal file
1250
static/country_codes.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,14 +6,9 @@ body {
|
|||||||
margin: 1em auto 6em;
|
margin: 1em auto 6em;
|
||||||
}
|
}
|
||||||
#biglogo {
|
#biglogo {
|
||||||
width:75%;
|
width:65%;
|
||||||
}
|
max-width:650px;
|
||||||
.dark-panel {
|
min-width:250px;
|
||||||
background: -moz-linear-gradient(center top, #222222 0%, #313331 100%);
|
|
||||||
border: 5px solid #999999;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 2px 5px rgba(0,0,0,0.25);
|
|
||||||
color: #fff;
|
|
||||||
}
|
}
|
||||||
.uk-navbar-brand > img, .uk-navbar-flip > img {
|
.uk-navbar-brand > img, .uk-navbar-flip > img {
|
||||||
height:35px;
|
height:35px;
|
||||||
@ -58,3 +53,30 @@ footer {
|
|||||||
#streams-online > .uk-article > a > h4 {
|
#streams-online > .uk-article > a > h4 {
|
||||||
margin:0px;
|
margin:0px;
|
||||||
}
|
}
|
||||||
|
#tsviewer > .uk-modal-dialog {
|
||||||
|
max-height: 80%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ts_num {
|
||||||
|
color: #D9A859;
|
||||||
|
}
|
||||||
|
.dn-streamer, .dn-streamer-offline {
|
||||||
|
display: inline-block;
|
||||||
|
width: 110px;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
.dn-streamer-offline > img {
|
||||||
|
height:50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dn-streamer-hover {
|
||||||
|
background:red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dn-hero-icon {
|
||||||
|
background:#000;
|
||||||
|
padding:4px;
|
||||||
|
margin:2px;
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
background-repeat:no-repeat;
|
background-repeat:no-repeat;
|
||||||
overflow:visible;
|
overflow:visible;
|
||||||
text-transform:uppercase;
|
text-transform:uppercase;
|
||||||
color: rgba(105,211,50,0.75);
|
color: black;
|
||||||
padding:6px 10px 15px 40px;
|
padding:6px 10px 15px 40px;
|
||||||
}
|
}
|
||||||
#tavernAgility{
|
#tavernAgility{
|
||||||
|
@ -20,11 +20,10 @@
|
|||||||
{
|
{
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
white-space: nowrap;
|
white-space: normal;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tswv-link
|
.tswv-link
|
||||||
|
@ -8,10 +8,10 @@ from flask import url_for
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
from app import app
|
from app import app
|
||||||
from models import TeamspeakData
|
|
||||||
|
|
||||||
def getTeamspeakWindow(window=605800):
|
def getTeamspeakWindow(window=605800):
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
|
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 create_teamspeak_viewer():
|
def create_teamspeak_viewer():
|
||||||
@ -159,8 +159,11 @@ def create_teamspeak_viewer():
|
|||||||
return "error: %s" % inst
|
return "error: %s" % inst
|
||||||
|
|
||||||
def get_ISO3166_mapping():
|
def get_ISO3166_mapping():
|
||||||
data = requests.get('http://www.iso.org/iso/home/standards/country_codes/country_names_and_code_elements_xml.html')
|
#data = requests.get(url_for('static', filename='country_codes.xml'))
|
||||||
xml = ElementTree.fromstring(data.text.encode('utf-8'))
|
#xml = ElementTree.fromstring(data.text.encode('utf-8'))
|
||||||
|
with open('app/static/country_codes.xml', mode='r') as d:
|
||||||
|
data = d.read()
|
||||||
|
xml = ElementTree.fromstring(data)
|
||||||
d = dict()
|
d = dict()
|
||||||
for entry in xml.findall('ISO_3166-1_Entry'):
|
for entry in xml.findall('ISO_3166-1_Entry'):
|
||||||
d[entry.find('ISO_3166-1_Alpha-2_Code_element').text] = entry.find('ISO_3166-1_Country_name').text
|
d[entry.find('ISO_3166-1_Alpha-2_Code_element').text] = entry.find('ISO_3166-1_Country_name').text
|
||||||
|
87
templates/hero_random.html
Normal file
87
templates/hero_random.html
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block head %}
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/heropedia.css') }}" >
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block title %} A-Z Challenge: {{ user.nickname }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% set taverns = heropedia() %}
|
||||||
|
<h2 class="uk-text-center">{{ user.nickname }}'s A-Z Challenge</h2>
|
||||||
|
<hr />
|
||||||
|
<div class="uk-grid">
|
||||||
|
<div class="uk-width-large-1-3 uk-width-medium-1-1 uk-panel uk-text-center uk-margin-bottom">
|
||||||
|
<h3 class="uk-panel-title">Current Hero</h3>
|
||||||
|
<h4 class="uk-text-bold uk-margin-remove">{{ user.random_hero['localized_name'] }}</h4>
|
||||||
|
<img src="{{ url_for('static', filename=hero_image_large(user.random_hero)) }}" class="dn-hero-icon" />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span id="heroes_completed">Heroes Completed: {{ user.random_heroes.completed | length }}</span><br/>
|
||||||
|
<span id="heroes_left">Heroes Left: {{ total_hero_pool() - user.random_heroes.completed|length }}</span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% if g.user and g.user.steamid == user.steamid %}
|
||||||
|
<form action="{{ url_for('user_random_hero', userid=g.user.id) }}" method="post" id="random_form" class="uk-margin">
|
||||||
|
<input type="checkbox" name="completed" id="completed_checkbox" style="display:none;">
|
||||||
|
<input type="checkbox" name="skip" id="skip_checkbox" style="display:none;">
|
||||||
|
<a class="uk-button uk-button-success" id="completed_button">Completed!</a>
|
||||||
|
<a class="uk-button uk-button-primary" id="skip_button">Skip</a>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="uk-width-large-2-3 uk-width-medium-1-1 uk-panel uk-text-center uk-margin">
|
||||||
|
<div class="uk-badge uk-panel-badge uk-badge-notification uk-badge-success">x1</div>
|
||||||
|
<h3 class="uk-panel-title">Completed</h3>
|
||||||
|
{% for hero in user.random_heroes.completed %}
|
||||||
|
<img src="{{ url_for('static', filename=hero_image_small(hero)) }}" class="dn-hero-icon" />
|
||||||
|
{% endfor %}
|
||||||
|
<br/><br/>
|
||||||
|
<br/><br/>
|
||||||
|
</div>
|
||||||
|
<div class="uk-width-large-2-3 uk-width-medium-1-1 uk-container-center">
|
||||||
|
<ul class="uk-tab" data-uk-tab="{connect:'#taverns'}">
|
||||||
|
<li class="uk-active"><a href="">Strength</a></li>
|
||||||
|
<li><a href="">Agility</a></li>
|
||||||
|
<li><a href="">Intelligence</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul id="taverns" class="uk-switcher uk-margin">
|
||||||
|
<li><div class="uk-panel tavern">
|
||||||
|
<label id="tavernStrength">Strength</label>
|
||||||
|
{% for hero in taverns[0][1] + taverns[3][1] %}
|
||||||
|
<img class="{{hero['name'] in user.random_completed and 'filterUnmatchedHero' or 'filterMatchedHero' }}" id="{{ hero['name'] }}" src="{{ url_for('static', filename=hero_image_small(hero)) }}" />
|
||||||
|
{% endfor %}
|
||||||
|
</div></li>
|
||||||
|
<li><div class="uk-panel tavern">
|
||||||
|
<label id="tavernAgility">Agility</label>
|
||||||
|
{% for hero in taverns[1][1] + taverns[4][1] %}
|
||||||
|
<img class="{{hero['name'] in user.random_completed and 'filterUnmatchedHero' or 'filterMatchedHero' }}" id="{{ hero['name'] }}" src="{{ url_for('static', filename=hero_image_small(hero)) }}" />
|
||||||
|
{% endfor %}
|
||||||
|
</div> </li>
|
||||||
|
<li><div class="uk-panel tavern">
|
||||||
|
<label id="tavernIntelligence">Intelligence</label>
|
||||||
|
{% for hero in taverns[2][1] + taverns[5][1] %}
|
||||||
|
<img class="{{hero['name'] in user.random_completed and 'filterUnmatchedHero' or 'filterMatchedHero' }}" id="{{ hero['name'] }}" src="{{ url_for('static', filename=hero_image_small(hero)) }}" />
|
||||||
|
{% endfor %}
|
||||||
|
</div> </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% if g.user and g.user.id == user.id %}
|
||||||
|
{% block pagescripts %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#completed_button').click( function() {
|
||||||
|
$('#completed_checkbox').attr('checked', true);
|
||||||
|
$('#random_form').submit();
|
||||||
|
});
|
||||||
|
$('#skip_button').click( function() {
|
||||||
|
$('#skip_checkbox').attr('checked', true);
|
||||||
|
$('#random_form').submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
{% endif %}
|
@ -5,163 +5,128 @@
|
|||||||
{% 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() %}
|
||||||
<div class="uk-grid" data-uk-grid-margin>
|
<div class="uk-grid">
|
||||||
<div class="uk-width-large-1-2 uk-width-medium-1-1">
|
<div class="uk-width-large-1-2 uk-width-medium-1-1 uk-panel uk-panel-space">
|
||||||
<div class=" uk-panel uk-panel-space">
|
<h1 class="uk-panel-title">Events</h1>
|
||||||
<h1 class="uk-panel-title">Who Are The Doobs!?</h1>
|
{#
|
||||||
<p>Welcome to DotaNoobs! We are a community formed by a group of redditors in an effort to provide a fun and rage-free environment for Dota2 players of all skill levels to enjoy the game and learn from each other. We have a TeamSpeak server open to the public for voice communication; hopping into the server is the best way to get involved, so click on "Server" to the right to get started. </p>
|
{% if active_event %}
|
||||||
<div id="about-us-more">
|
<article class="uk-article">
|
||||||
<p>Be sure to visit the forum board to keep in touch with the community even when not playing. Create an account, introduce yourself, and chat about all things DotA.</p>
|
<h4>Right Now</h4>
|
||||||
<p>There is a "Dota Noobs" chat room inside the game client, and a "DotaNoobs" guild to help organzie games outside of TeamSpeak. Ask an admin for an invite today!</p>
|
<a href="{{ url_for('event_summary', eventid=active_event._id) }}">{{ active_event.name }}</a>
|
||||||
</div>
|
<p class="uk-article-meta">Ends at: {{ timestamp_to_js_date(active_event.end_time) }}</p>
|
||||||
<button class="uk-button uk-button-small uk-float-right" id="more">More <i class="uk-icon-angle-down"></i></button>
|
</article>
|
||||||
<button class="uk-button uk-button-small uk-float-right" id="less">Less <i class="uk-icon-angle-up"></i></button>
|
{% endif %}
|
||||||
</div>
|
{% if upcoming_event %}
|
||||||
</div>
|
<article class="uk-article">
|
||||||
<div class="uk-width-large-1-2 uk-width-medium-1-1">
|
<h4>Next Event</h4>
|
||||||
<div class="uk-panel uk-panel-space uk-panel-box">
|
<a href="{{ url_for('event_summary', eventid=upcoming_event._id) }}">{{ upcoming_event.name }}</a>
|
||||||
<a href="ts3server://voice.dotanoobs.com"><div class="uk-panel-badge uk-badge uk-badge-success"><i class="uk-icon-microphone"> Connect to Teamspeak</i></div></a>
|
<p class="uk-article-meta">Starts at: {{ timestamp_to_js_date(upcoming_event.start_time) }}</p>
|
||||||
<h1 class="uk-panel-title">Our TeamSpeak Server</h1>
|
</article>
|
||||||
<ul>
|
{% else %}
|
||||||
<li>Current Users: {{ ts3_current_clients() }}</li>
|
|
||||||
<li>Active Countries: {{ ts3_countries_active(teamspeak_data) }}</li>
|
|
||||||
</ul>
|
|
||||||
<button class="uk-button" data-uk-modal="{target:'#tsviewer'}">Viewer</button>
|
|
||||||
<a class="uk-button" href="{{ url_for('teamspeak') }}">Statistics</a>
|
|
||||||
|
|
||||||
<hr class="uk-panel-divider" />
|
|
||||||
|
|
||||||
|
|
||||||
<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>
|
<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 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">
|
||||||
|
<div class="uk-width-1-3 uk-panel">
|
||||||
|
<h3>Users<br/><span class="ts_num">{{ ts3_current_clients() }}</span></h3>
|
||||||
|
</div>
|
||||||
|
<div class="uk-width-1-3 uk-panel">
|
||||||
|
<h3 class="uk-text-success">Online</h3>
|
||||||
|
</div>
|
||||||
|
<div class="uk-width-1-3 uk-panel">
|
||||||
|
<h3>Countries<br/><span class="ts_num">{{ ts3_countries_active(teamspeak_data) }}</span></h3>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="tsviewer" class="uk-modal">
|
|
||||||
|
<a class="uk-button uk-button-success uk-width-1-1" href="ts3server://voice.dotanoobs.com"><i class="uk-icon-microphone"></i> Connect</a>
|
||||||
|
<a class="uk-button uk-width-1-1 uk-margin" href="{{ url_for('teamspeak') }}"><i class="uk-icon-globe"></i> Stats</a>
|
||||||
|
<a class="uk-button uk-width-1-1" href="http://www.teamspeak.com/?page=downloads"><i class="uk-icon-download"></i> Download</a>
|
||||||
|
|
||||||
|
<div id="tsviewer" class="uk-modal uk-text-left">
|
||||||
<div class="uk-modal-dialog">
|
<div class="uk-modal-dialog">
|
||||||
<a class="uk-modal-close uk-close"></a>
|
<a class="uk-modal-close uk-close"></a>
|
||||||
{{ ts3_viewer() | safe }}
|
{{ ts3_viewer() | safe }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="streams" class="uk-width-1-1 uk-text-center uk-panel uk-panel-space">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-width-1-1 uk-panel uk-panel-header">
|
||||||
|
<h4 class="uk-panel-title">News and Announcements</h4>
|
||||||
|
{% 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>
|
||||||
|
<p class="uk-article-meta">{{ news['date'] }}</p>
|
||||||
|
<p>{{ news['text'] | shorten }}</p>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="uk-grid" data-uk-grid-margin>
|
{#{% endcache %}#}
|
||||||
<div class="uk-width-large-2-3 uk-width-medium-1-1">
|
|
||||||
<div class="uk-panel uk-panel-space uk-panel-box uk-panel-header">
|
|
||||||
<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 uk-text-truncate" data-uk-tooltip="{pos:'bottom-right'}" title="{{ news['title'] }}"><a href="{{ news['url'] }}">{{ news['title'] }}</a></h4>
|
|
||||||
<p class="uk-article-meta">{{ news['date'] }}</p>
|
|
||||||
<p>{{ news['text'] | shorten }}</p>
|
|
||||||
</article>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{#
|
|
||||||
<div class="uk-hidden-large uk-width-medium-1-1">
|
|
||||||
<div class="uk-panel uk-panel-space uk-panel-box uk-panel-header">
|
|
||||||
<a href="{{ url_for('list_events') }}"><div class="uk-panel-badge uk-badge uk-badge-success"><i class="uk-icon-calendar"> View All Events</i></div></a>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
#}
|
|
||||||
<div class="uk-width-large-1-3 uk-width-medium-1-1">
|
|
||||||
<div class="uk-panel uk-panel-space">
|
|
||||||
<h1 class="uk-panel-title">Live Streams</h1>
|
|
||||||
<ul id="streams-online"></ul>
|
|
||||||
<hr id="stream-divider" class="uk-article-divider" style="display:none;" />
|
|
||||||
<ul id="streams-offline"></ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endcache %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block pagescripts %}
|
{% block pagescripts %}
|
||||||
<script>
|
<script>
|
||||||
|
{% cache 60*5 %}
|
||||||
$(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 = ["dotanoobs", "bearhugdota", "kreejaffakree", "prettypenguins", "shaneomad"];
|
var channels = ["dotanoobs", "bearhugdota", "kreejaffakree", "prettypenguins", "shaneomad"];
|
||||||
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 = "<span 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 + "</span>";
|
|
||||||
$(jquery_selector).append(span_text);
|
$a.append($strm);
|
||||||
$(jquery_selector).append("<img src='" + data.stream.preview.medium + "' />")
|
$("#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 %}
|
{% endcache %}
|
||||||
|
|
||||||
|
|
||||||
|
$(".dn-streamer, .dn-streamer-offline").on({
|
||||||
|
mouseover: function() {
|
||||||
|
$(this).addClass('dn-streamer-hover');
|
||||||
|
},
|
||||||
|
mouseleave: function() {
|
||||||
|
$(this).removeClass('dn-streamer-hover');
|
||||||
|
}
|
||||||
|
}, "div");
|
||||||
|
|
||||||
// Localize the events
|
// Localize the events
|
||||||
$('.date').each( function( index ) {
|
$('.date').each( function( index ) {
|
||||||
var d = new Date($(this).text());
|
var d = new Date($(this).text());
|
||||||
$(this).text( d.toLocaleDateString() + ' @ ' + d.toLocaleTimeString() );
|
$(this).text( d.toLocaleDateString() + ' @ ' + d.toLocaleTimeString() );
|
||||||
});
|
});
|
||||||
|
|
||||||
// About-us toggle
|
|
||||||
$('#more,#less').click(function() {
|
|
||||||
$('#more').toggle();
|
|
||||||
$('#less').toggle();
|
|
||||||
$('#about-us-more').toggle();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<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="{{ url_for('static', filename='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') }}" />
|
||||||
|
|
||||||
@ -22,36 +23,18 @@
|
|||||||
<nav class="uk-navbar uk-navbar-attached" data-uk-navbar>
|
<nav class="uk-navbar uk-navbar-attached" data-uk-navbar>
|
||||||
<a href="#offcanvas" class="uk-navbar-brand uk-hidden-large" data-uk-offcanvas><img src="{{ url_for('static', filename='img/navlogo.png') }}" /><i class="uk-icon-double-angle-down"></i></a>
|
<a href="#offcanvas" class="uk-navbar-brand uk-hidden-large" data-uk-offcanvas><img src="{{ url_for('static', filename='img/navlogo.png') }}" /><i class="uk-icon-double-angle-down"></i></a>
|
||||||
<a href="" class="uk-navbar-brand uk-visible-large" data-uk-offcanvas><img src="{{ url_for('static', filename='img/navlogo.png') }}" /></a>
|
<a href="" class="uk-navbar-brand uk-visible-large" data-uk-offcanvas><img src="{{ url_for('static', filename='img/navlogo.png') }}" /></a>
|
||||||
{# /* In header drop-down navigation, possibly reenable as static "you are here" marker */
|
|
||||||
<ul class="uk-navbar-nav">
|
|
||||||
<li data-uk-dropdown="" class="uk-parent">
|
|
||||||
<a href="{{ url_for('main') }}"><i class="uk-icon-home"></i> Home</a>
|
|
||||||
<div class="uk-dropdown uk-dropdown-navbar">
|
|
||||||
<ul class="uk-nav uk-nav-navbar">
|
|
||||||
<li><a href="http://board.dotanoobs.com">Board</a></li>
|
|
||||||
<li><a href="{{ url_for('teamspeak') }}">TeamSpeak</a></li>
|
|
||||||
<li class="uk-nav-header">Doobs</li>
|
|
||||||
<li><a href="{{ url_for('doobs_stuff.list_events') }}">Events</a></li>
|
|
||||||
<li><a href="{{ url_for('doobs_stuff.ladder') }}">Ladder</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
#}
|
|
||||||
<!-- Check if user is logged in -->
|
<!-- Check if user is logged in -->
|
||||||
{% if g.user %}
|
{% if g.user %}
|
||||||
<ul class="uk-navbar-nav uk-navbar-flip">
|
<ul class="uk-navbar-nav uk-navbar-flip">
|
||||||
<li data-uk-dropdown="" class="uk-parent">
|
<li data-uk-dropdown="" class="uk-parent">
|
||||||
<a href="#"><img class="uk-responsive-height" src="{{ g.user.avatar
|
<a href="#"><img class="uk-responsive-height" src="{{ g.user.avatar }}" /> {{ g.user.nickname }} </a>
|
||||||
}}" /> {{ g.user.nickname }} </a>
|
|
||||||
<div class="uk-dropdown uk-dropdown-navbar">
|
<div class="uk-dropdown uk-dropdown-navbar">
|
||||||
<ul class="uk-nav uk-nav-navbar">
|
<ul class="uk-nav uk-nav-navbar">
|
||||||
{#
|
<li><a href="{{ url_for('user_profile', userid=g.user.id) }}">Profile</a></li>
|
||||||
<li><a href="{{ url_for('doobs_stuff.doob_summary', playerid=g.doob._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('doobs_stuff.doob_random', playerid=g.doob._id) }}">A-Z Challenge</a></li>
|
<li><a href="http://board.dotanoobs.com/?page=lastposts">Latest Posts</a></li>
|
||||||
<!--<li class="uk-disabled"><a href="">Recent Events</a></li>-->
|
|
||||||
<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('logout') }}">Logout</a></li>
|
<li><a href="{{ url_for('logout') }}">Logout</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -65,10 +48,10 @@
|
|||||||
<!-- Flash Error Messages -->
|
<!-- Flash Error Messages -->
|
||||||
{% with messages = get_flashed_messages() %}
|
{% with messages = get_flashed_messages() %}
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
<ul class="flashes">
|
<ul class="flashes uk-width-1-3 uk-container-center">
|
||||||
<a href="" class="uk-alert-close uk-close"></a>
|
<a href="" class="uk-alert-close uk-close"></a>
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
<li class="uk-alert uk-alert-danger">{{ category }}:{{ message }}</li>
|
<li class="uk-alert uk-alert-danger">{{ message }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -79,12 +62,12 @@
|
|||||||
<!-- Big top logo -->
|
<!-- Big top 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>
|
||||||
<!-- Side navigation -->
|
<!-- Side navigation -->
|
||||||
<div class="uk-visible-large uk-width-1-5 uk-panel uk-panel-box">
|
<div class="uk-visible-large uk-width-1-5 uk-panel">
|
||||||
{% if g.doob%}
|
{% if g.doob%}
|
||||||
<h3 class="uk-panel-title">{{ g.doob.name }}</h3>
|
<h3 class="uk-panel-title">{{ g.doob.name }}</h3>
|
||||||
<hr class="uk-nav-divider" />
|
<hr class="uk-nav-divider" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<ul class="uk-nav uk-nav-side">
|
<ul class="uk-nav uk-nav-side uk-text-right uk-nav-parent-icon" data-uk-nav>
|
||||||
{% include 'sidenav.html' %}
|
{% include 'sidenav.html' %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,29 +4,38 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="uk-grid" data-uk-grid-margin>
|
<div class="uk-grid" data-uk-grid-margin>
|
||||||
<div class="uk-width-1-1 uk-panel">
|
<div class="uk-width-2-3">
|
||||||
<img class="uk-align-center" src="{{ user.avatar }}" />
|
<h2 class="uk-float-left"><img class="" src="{{ user.avatar }}" /> {{ user.nickname }}</h2>
|
||||||
<h2 class="uk-panel-title uk-text-center">Profile for {{ 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>
|
</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">
|
||||||
<div class="uk-panel">
|
{% if user.bio_text == None %}
|
||||||
main content area
|
<em class="uk-text-danger">This user's profile bio is empty!</em>
|
||||||
</div>
|
{% else %}
|
||||||
|
<em class="uk-text-bold">{{ user.bio_text }}</em>
|
||||||
|
{% 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">
|
<div class="uk-width-large-1-3 uk-width-medium-1-1 uk-panel uk-panel-box uk-panel-box-secondary">
|
||||||
<ul>
|
|
||||||
<li>Points [value]</li>
|
|
||||||
<li><a href="http://board.dotanoobs.com/?page=profile&id={{ user.id | safe }}">Forum Profile</a>
|
|
||||||
<li>Last seen on TeamSpeak: [value]<li>
|
|
||||||
</ul>
|
|
||||||
<hr class="uk-panel-divider" />
|
|
||||||
<div class="uk-container-center uk-text-center">
|
<div class="uk-container-center uk-text-center">
|
||||||
Randomstats
|
<span class="uk-text-bold">Current Hero</span><br/>
|
||||||
<span>Current Hero</span>
|
<span>{{ user.random_hero['localized_name'] }}</span><br/>
|
||||||
Heroimg
|
<a href={{ url_for('user_random_hero', userid=user.id) }}>
|
||||||
|
<img src="{{ url_for('static', filename=hero_image_large(user.random_hero)) }}" class="dn-hero-icon" /><br/>
|
||||||
|
<span>View A-Z Progress</span>
|
||||||
|
</a>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
41
templates/settings.html
Normal file
41
templates/settings.html
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block title %}Settings for {{ g.user.nickname }} - DotaNoobs {% endblock %}
|
||||||
|
|
||||||
|
{% 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>
|
||||||
|
</div>
|
||||||
|
<div class="uk-width-1-3 uk-text-center">
|
||||||
|
</div>
|
||||||
|
<!--Main content area -->
|
||||||
|
<div class="uk-width-large-2-3 uk-width-medium-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>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="uk-form-row">
|
||||||
|
<label class="uk-form-label">Twitch.tv Username:</label> <br/>
|
||||||
|
{{ form.twitch(placeholder="e.g. shaneomad") }}
|
||||||
|
</div>
|
||||||
|
<div class="uk-form-row">
|
||||||
|
<label class="uk-form-label">Biography text:</label><br/>
|
||||||
|
{{ form.bio_text(rows=14, class='uk-width-1-1', data=g.user.bio_text, placedholder='What you place here is displayed in your profile when other users view it.') }}
|
||||||
|
</div>
|
||||||
|
<div class="uk-form-controls uk-margin-top">
|
||||||
|
<button class="uk-button uk-button-success" type="submit">Save</button>
|
||||||
|
<a class="uk-button" href="{{ url_for('user_profile', userid=g.user.id) }}">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -2,13 +2,19 @@
|
|||||||
('index', 'Home'),
|
('index', 'Home'),
|
||||||
('friends', 'Friends'),
|
('friends', 'Friends'),
|
||||||
('list_events', 'Events'),
|
('list_events', 'Events'),
|
||||||
('community', 'Community'),
|
('teamspeak', 'TS3 Stats'),
|
||||||
('ladder', 'Ladder'),
|
|
||||||
] %}
|
] %}
|
||||||
<li{% if endpoint == request.endpoint %} class='uk-active' {% endif %}>
|
<li{% if endpoint == request.endpoint %} class='uk-active' {% endif %}>
|
||||||
<a href="{{ url_for(endpoint) }}">{{ title }}</a>
|
<a href="{{ url_for(endpoint) }}">{{ title }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<li class="uk-parent">
|
||||||
|
<a href="#">Stream Stats</a>
|
||||||
|
<ul class="uk-nav-sub">
|
||||||
|
<li><a href="http://potatr.dotanoobs.com">Potato_Bot</a></li>
|
||||||
|
<li><a href="http://potatr.dotanoobs.com">Cider_Bot</a></li>
|
||||||
|
</ul>
|
||||||
|
</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"> Board</i></a></li>
|
||||||
@ -20,6 +26,6 @@
|
|||||||
<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-cog"> Register</i></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-home"> Profile</i></a></li>
|
||||||
<li><a href="{{ url_for('user_profile', userid=g.user.id) }}"><i class="uk-icon-cog"> Settings</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><a href="{{ url_for('logout') }}"><i class="uk-icon-off"> Logout</i></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<h3 class="uk-text-bold uk-text-center">Current Status</h3>
|
<h3 class="uk-text-bold uk-text-center">Current Status</h3>
|
||||||
<a class="uk-button uk-button-success" href="ts3server://voice.dotanoobs.com">Connect</a>
|
<a class="uk-button uk-button-success" href="ts3server://voice.dotanoobs.com">Connect</a>
|
||||||
<a class="uk-button uk-button-primary" href="http://www.teamspeak.com/download">Download</a>
|
<a class="uk-button uk-button-primary" href="http://www.teamspeak.com/download">Download</a>
|
||||||
<h5>Server: voice.dotanoobs.com</h5>
|
<h5><strong>Server: voice.dotanoobs.com</strong></h5>
|
||||||
<div class="uk-panel uk-text-left">
|
<div class="uk-panel uk-text-left">
|
||||||
{{ ts3_viewer() | safe }}
|
{{ ts3_viewer() | safe }}
|
||||||
</div>
|
</div>
|
||||||
|
69
utils.py
69
utils.py
@ -1,6 +1,10 @@
|
|||||||
import requests
|
import requests
|
||||||
import re
|
import re
|
||||||
from time import strptime, strftime, gmtime
|
from time import strptime, strftime, gmtime
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from itertools import product
|
||||||
|
from os import path, makedirs
|
||||||
|
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
from app import app, cache
|
from app import app, cache
|
||||||
from teamspeak import create_teamspeak_viewer, getTeamspeakWindow, ISO3166_MAPPING
|
from teamspeak import create_teamspeak_viewer, getTeamspeakWindow, ISO3166_MAPPING
|
||||||
@ -10,13 +14,36 @@ def get_steam_userinfo(steam_id):
|
|||||||
'key': app.config['DOTA2_API_KEY'],
|
'key': app.config['DOTA2_API_KEY'],
|
||||||
'steamids': steam_id
|
'steamids': steam_id
|
||||||
}
|
}
|
||||||
data = requests.get('http://api.steampowered.com/ISteamUser/' \
|
data = requests.get('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0001/', params=options).json()
|
||||||
'GetPlayerSummaries/v0001/', params=options).json()
|
|
||||||
return data['response']['players']['player'][0] or {}
|
return data['response']['players']['player'][0] or {}
|
||||||
|
|
||||||
|
def get_api_hero_data():
|
||||||
|
data = requests.get("https://api.steampowered.com/IEconDOTA2_570/GetHeroes/v0001/?key="+app.config['DOTA2_API_KEY']+"&language=en_us").json()
|
||||||
|
return data
|
||||||
|
|
||||||
|
API_DATA = get_api_hero_data()
|
||||||
|
|
||||||
|
def complete_hero_data(key, value):
|
||||||
|
# Possible keys are id, localized_name and name
|
||||||
|
for hero_data in API_DATA['result']['heroes']:
|
||||||
|
if hero_data[key] == value: return hero_data
|
||||||
|
|
||||||
|
def get_hero_data_by_id(hero_id):
|
||||||
|
return API_DATA['result']['heroes'][hero_id-1]
|
||||||
|
|
||||||
|
def parse_valve_heropedia():
|
||||||
|
data = requests.get('http://www.dota2.com/heroes/')
|
||||||
|
soup = BeautifulSoup(data.text)
|
||||||
|
taverns = []
|
||||||
|
tavern_names = [' '.join(entry) for entry in product(('Radiant', 'Dire'), ('Strength', 'Agility', 'Intelligence'))]
|
||||||
|
for tavern_name, tavern in zip(tavern_names, soup.find_all(class_=re.compile('^heroCol'))):
|
||||||
|
img_base = lambda tag: tag.name == 'img' and 'base' in tag.get('id')
|
||||||
|
taverns.append((tavern_name, [complete_hero_data('name', 'npc_dota_hero_%s' % tag['id'].replace('base_', '')) for tag in tavern.find_all(img_base)]))
|
||||||
|
return taverns
|
||||||
|
|
||||||
# For Templates
|
# For Templates
|
||||||
@app.template_filter('shorten')
|
@app.template_filter('shorten')
|
||||||
def shorten_filter(s, num_words=20):
|
def shorten_filter(s, num_words=40):
|
||||||
space_iter = re.finditer('\s+', s)
|
space_iter = re.finditer('\s+', s)
|
||||||
output = u''
|
output = u''
|
||||||
while num_words > 0:
|
while num_words > 0:
|
||||||
@ -30,6 +57,7 @@ def shorten_filter(s, num_words=20):
|
|||||||
|
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
def utility_processor():
|
def utility_processor():
|
||||||
|
''' For Teamspeak '''
|
||||||
@cache.memoize(60*5)
|
@cache.memoize(60*5)
|
||||||
def ts3_viewer():
|
def ts3_viewer():
|
||||||
html = create_teamspeak_viewer()[0]
|
html = create_teamspeak_viewer()[0]
|
||||||
@ -63,6 +91,38 @@ def utility_processor():
|
|||||||
for key, name in ISO3166_MAPPING.iteritems():
|
for key, name in ISO3166_MAPPING.iteritems():
|
||||||
mapping[key.lower()] = ' '.join([word.capitalize() for word in name.split(' ')])
|
mapping[key.lower()] = ' '.join([word.capitalize() for word in name.split(' ')])
|
||||||
return mapping
|
return mapping
|
||||||
|
''' Dota2 info '''
|
||||||
|
def total_hero_pool():
|
||||||
|
return len(API_DATA['result']['heroes'])
|
||||||
|
def hero_image_large(hero_data):
|
||||||
|
if type(hero_data) is unicode:
|
||||||
|
stripped_name = hero_data.replace('npc_dota_hero_', '')
|
||||||
|
else:
|
||||||
|
stripped_name = hero_data['name'].replace('npc_dota_hero_', '')
|
||||||
|
img_file = path.join(app.config['HERO_IMAGE_PATH'], stripped_name + '.png')
|
||||||
|
img_src = path.join(app.root_path, app.static_folder, img_file)
|
||||||
|
if not path.exists(img_src):
|
||||||
|
i = requests.get('http://media.steampowered.com/apps/dota2/images/heroes/{}_hphover.png'.format(stripped_name)).content
|
||||||
|
if not path.exists(path.split(img_src)[0]):
|
||||||
|
makedirs(path.split(img_src)[0])
|
||||||
|
with open(img_src, 'wb') as img:
|
||||||
|
img.write(i)
|
||||||
|
return img_file
|
||||||
|
def hero_image_small(hero_data):
|
||||||
|
if type(hero_data) is unicode:
|
||||||
|
stripped_name = hero_data.replace('npc_dota_hero_', '')
|
||||||
|
else:
|
||||||
|
stripped_name = hero_data['name'].replace('npc_dota_hero_', '')
|
||||||
|
img_file = path.join(app.config['HERO_IMAGE_PATH'], stripped_name + '_small.png')
|
||||||
|
img_src = path.join(app.root_path, app.static_folder, img_file)
|
||||||
|
if not path.exists(img_src):
|
||||||
|
i = requests.get('http://media.steampowered.com/apps/dota2/images/heroes/{}_sb.png'.format(stripped_name)).content
|
||||||
|
if not path.exists(path.split(img_src)[0]):
|
||||||
|
makedirs(path.split(img_src)[0])
|
||||||
|
with open(img_src, 'wb') as img:
|
||||||
|
img.write(i)
|
||||||
|
return img_file
|
||||||
|
''' Misc '''
|
||||||
def timestamp_to_js_date(timestamp):
|
def timestamp_to_js_date(timestamp):
|
||||||
return strftime('%B %d, %Y %H:%M:%S UTC', gmtime(timestamp))
|
return strftime('%B %d, %Y %H:%M:%S UTC', gmtime(timestamp))
|
||||||
def js_date_to_timestamp(date):
|
def js_date_to_timestamp(date):
|
||||||
@ -70,4 +130,5 @@ def utility_processor():
|
|||||||
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, timestamp_to_js_date=timestamp_to_js_date, js_date_to_timestamp=js_date_to_timestamp, \
|
||||||
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)
|
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)
|
||||||
|
99
views.py
99
views.py
@ -1,18 +1,22 @@
|
|||||||
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 app import app, db, oid, cache
|
from app import app, db, oid, cache
|
||||||
from models import User
|
from models import User
|
||||||
from utils import get_steam_userinfo
|
from utils import get_steam_userinfo
|
||||||
from board import latest_news
|
from board import latest_news
|
||||||
|
from forms import SettingsForm
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def before_request():
|
def before_request():
|
||||||
g.user = None
|
g.user = None
|
||||||
if 'user_id' in session:
|
if 'user_id' in session:
|
||||||
g.user = User.query.get(session['user_id'])
|
g.user = User.query.get(session['user_id'])
|
||||||
|
if g.user:
|
||||||
|
g.user.last_seen = datetime.utcnow()
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
@app.route('/main')
|
|
||||||
def index():
|
def index():
|
||||||
return render_template("index.html", latest_news=latest_news())
|
return render_template("index.html", latest_news=latest_news())
|
||||||
|
|
||||||
@ -32,7 +36,7 @@ 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))
|
||||||
return redirect(oid.get_next_url())
|
return redirect(oid.get_next_url())
|
||||||
|
|
||||||
@app.route('/logout')
|
@app.route('/logout')
|
||||||
@ -42,69 +46,56 @@ def logout():
|
|||||||
|
|
||||||
|
|
||||||
### TEMPORARY ###
|
### TEMPORARY ###
|
||||||
@app.route('/teamspeak')
|
|
||||||
def teamspeak():
|
|
||||||
return render_template('teamspeak.html')
|
|
||||||
@app.route('/list_events')
|
@app.route('/list_events')
|
||||||
def list_events():
|
def list_events():
|
||||||
return "Events list!"
|
return "Events list!"
|
||||||
@app.route('/friends')
|
|
||||||
def friends():
|
|
||||||
return render_template('friends.html')
|
|
||||||
@app.route('/community')
|
@app.route('/community')
|
||||||
def community():
|
def community():
|
||||||
return "Community!"
|
return "Community!"
|
||||||
@app.route('/ladder')
|
@app.route('/ladder')
|
||||||
def ladder():
|
def ladder():
|
||||||
return "Ladder!"
|
return "Ladder!"
|
||||||
|
### ###
|
||||||
|
|
||||||
#From league/doobs_blueprint.py
|
|
||||||
@app.route('/profile/<int:userid>')
|
# Teamspeak statistics page
|
||||||
|
@app.route('/teamspeak')
|
||||||
|
def teamspeak():
|
||||||
|
return render_template('teamspeak.html')
|
||||||
|
|
||||||
|
# Friends of doobs page
|
||||||
|
@app.route('/friends')
|
||||||
|
def friends():
|
||||||
|
return render_template('friends.html')
|
||||||
|
|
||||||
|
# User profile page
|
||||||
|
@app.route('/user/<int:userid>')
|
||||||
def user_profile(userid):
|
def user_profile(userid):
|
||||||
user = User.query.filter_by(id=userid).first_or_404()
|
user = User.query.filter_by(id=userid).first_or_404()
|
||||||
return render_template('profile.html', user=user)
|
return render_template('profile.html', user=user)
|
||||||
|
|
||||||
'''
|
# User random a-z challenge progress page
|
||||||
from flask import render_template, flash, redirect, g, request, url_for
|
@app.route('/user/<int:userid>/random', methods=['POST', 'GET'])
|
||||||
from app import app, oid
|
def user_random_hero(userid):
|
||||||
|
user = User.query.filter_by(id=userid).first_or_404()
|
||||||
|
if request.method == 'POST':
|
||||||
|
if request.form.get('skip', False):
|
||||||
|
user.random_skip()
|
||||||
|
elif request.form.get('completed', False):
|
||||||
|
user.random_success()
|
||||||
|
return render_template('hero_random.html', user=user)
|
||||||
|
|
||||||
@app.route('/login')
|
# User settings page
|
||||||
@oid.loginhandler
|
@app.route('/settings', methods=['POST', 'GET'])
|
||||||
def login():
|
def user_settings():
|
||||||
if g.user is not None:
|
user = User.query.filter_by(id=g.user.id).first_or_404()
|
||||||
return redirect(oid.get_next_url())
|
form = SettingsForm(obj=user)
|
||||||
return oid.try_login('http://www.steamcommunity.com/openid')
|
if form.validate_on_submit():
|
||||||
|
g.user.bio_text = form.bio_text.data
|
||||||
@oid.after_login
|
g.user.twitch = form.twitch.data
|
||||||
def check_login(resp):
|
db.session.commit()
|
||||||
match = app.config['STEAM_ID_RE'].search(resp.identity_url)
|
flash('Settings updated!')
|
||||||
return "none"
|
return render_template('profile.html', user=g.user)
|
||||||
|
else:
|
||||||
@app.route('/')
|
form.populate_obj(user)
|
||||||
def main():
|
return render_template('settings.html', user=g.user, form=form)
|
||||||
return render_template('main.html')
|
|
||||||
|
|
||||||
@app.route('/community')
|
|
||||||
def community():
|
|
||||||
return render_template('community.html', latest_posts=latest_posts())
|
|
||||||
|
|
||||||
@app.route('/friends')
|
|
||||||
def friends():
|
|
||||||
return render_template('friends.html')
|
|
||||||
|
|
||||||
@app.route('/teamspeak')
|
|
||||||
def teamspeak():
|
|
||||||
return render_template('teamspeak.html')
|
|
||||||
|
|
||||||
@app.route('/events')
|
|
||||||
def list_events():
|
|
||||||
return render_template('events.html')
|
|
||||||
|
|
||||||
@app.route('/events/<int:id>')
|
|
||||||
def event_summary(id):
|
|
||||||
return render_template('events.html')
|
|
||||||
|
|
||||||
@app.route('/ladder')
|
|
||||||
def ladder():
|
|
||||||
return render_template('ladder.html')
|
|
||||||
'''
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user