Compare commits

...

8 Commits

  1. 71
      app/models.py
  2. 4
      app/teamspeak.py
  3. 89
      app/templates/hero_random.html
  4. 1
      app/templates/layout.html
  5. 9
      app/templates/private_profile.html
  6. 19
      app/templates/profile.html
  7. 18
      app/views.py
  8. 34
      migrations/versions/50e77b6e7331_.py
  9. 5
      requirements.txt
  10. 14
      run.py

71
app/models.py

@ -1,6 +1,5 @@
import simplejson as json
from datetime import datetime
from random import choice
from datetime import datetime, timedelta
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy.ext.mutable import Mutable
@ -69,16 +68,14 @@ class User(db.Model):
nickname = db.Column(db.String(80))
avatar = db.Column(db.String(255))
admin = db.Column(db.Boolean)
bio_text = db.Column(db.String(4096))
created = db.Column(db.DateTime)
last_seen = db.Column(db.DateTime)
twitch = db.Column(db.String(60))
hitbox = db.Column(db.String(60))
random_heroes = db.Column(MutableDict.as_mutable(Json))
az_completions = db.Column(db.Integer)
admin = db.Column(db.Boolean)
public = db.Column(db.Boolean)
logo = db.Column(db.Boolean)
@ -89,7 +86,8 @@ class User(db.Model):
ts3_starttime = db.Column(db.DateTime)
ts3_endtime = db.Column(db.DateTime)
ts3_rewardtime = db.Column(db.DateTime)
ts3_connections = db.Column(MutableDict.as_mutable(Json))
ts3_stretch_award_time = db.Column(db.DateTime)
ts3_longest_stretch = db.Column(db.Interval)
last_post_reward = db.Column(db.Integer)
winrate_data = db.Column(MutableDict.as_mutable(Json))
@ -114,10 +112,9 @@ class User(db.Model):
def __init__(self, steam_id):
self.steam_id = steam_id
self.random_heroes = {'current':None, 'completed':[]}
self.az_completions = 0
self.ts3_connections = {'list':[]}
self.ts3_rewardtime = datetime.utcnow()
self.ts3_longest_stretch = timedelta()
self.created = datetime.utcnow()
self.last_seen = datetime.utcnow()
self.bio_text = None
@ -128,63 +125,32 @@ class User(db.Model):
self.public = True
self.biglogo = True
@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 entry['name'] not in self.random_heroes['completed']])
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'])
if len(API_DATA['result']['heroes']) - len(self.random_heroes['completed']) <= 0:
self.az_completions = self.az_completions + 1
del self.random_heroes['completed'][:]
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 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:
delta = (self.ts3_endtime - self.ts3_rewardtime)
duration = (delta.seconds % 3600) // 60
if duration > reward_threshold:
self.ts3_rewardtime = datetime.utcnow()
self.points_from_ts3 += 1
else:
self.ts3_rewardtime = datetime.utcnow()
# Update last_seen for web profile
self.last_seen = datetime.utcnow()
db.session.commit();
def finalize_connection(self):
self.ts3_connections['list'].append({'starttime': self.ts3_starttime, 'endtime': self.ts3_endtime})
self.ts3_startime = None
# Check for longest!
if self.ts3_endtime and self.ts3_starttime:
current_stretch = self.ts3_endtime - self.ts3_starttime
if current_stretch > self.ts3_longest_stretch:
self.ts3_longest_stretch = current_stretch
self.ts3_stretch_award_time = datetime.utcnow()
# Reset values
self.ts3_starttime = None
self.ts3_endtime = None
db.session.commit();
@ -193,6 +159,7 @@ class User(db.Model):
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
print("Old: {0}, New: {1}, ({0} - {1}) / {2}, {3}, {4}".format(self.last_post_reward, posts, reward_threshold, num_points, self.nickname))
if num_points > 0:
self.points_from_forum += num_points
self.last_post_reward += num_points * reward_threshold
@ -308,7 +275,7 @@ class Event(db.Model):
@property
def expired(self):
current_time = datetime.utcnow()
return self.end_time < curent_time
return self.end_time < current_time
def add_participant(self, user):
entry = self.participants.setdefault(user, {'start_time': datetime.utcnow() })

4
app/teamspeak.py

@ -348,6 +348,7 @@ def award_idle_ts3_points(server):
for channel in list_response.data:
if exempt_check(channel['cid']):
exempt_cids.append(channel['cid'])
# Get list of clients
clientlist = server.clientlist()
for clid, client in clientlist.iteritems():
@ -366,6 +367,7 @@ def award_idle_ts3_points(server):
active_users.add(doob)
except KeyError:
pass
doobs = set(models.User.query.filter(models.User.ts3_starttime != None).all())
for doob in doobs.intersection(active_users):
for doob in doobs.difference(active_users):
doob.finalize_connection()

89
app/templates/hero_random.html

@ -1,89 +0,0 @@
{% 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.steam_id == user.steam_id %}
<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">
{% if user.az_completions > 0 %}
<div class="uk-badge uk-panel-badge uk-badge-notification uk-badge-success">x{{ user.az_completions }}</div>
{% endif %}
<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 %}

1
app/templates/layout.html

@ -35,7 +35,6 @@
<div class="uk-dropdown uk-dropdown-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('user_random_hero', userid=g.user.id) }}">A-Z Challenge</a></li>
<li><a href="http://board.dotanoobs.com/?page=lastposts">Latest Posts</a></li>
{% if g.user.admin %}
<li><a href="{{ url_for('event_edit') }}">Add Event</a></li>

9
app/templates/private_profile.html

@ -15,16 +15,7 @@
</div>
<!-- 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-container-center uk-text-center">
<span class="uk-text-bold">Current Hero</span><br/>
<span>{{ user.random_hero['localized_name'] }}</span><br/>
<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>
<ul class="uk-list uk-list-space uk-list-striped uk-text-center">
<li>Completed <span id='rands'>{{ user.random_heroes.completed | length }}</span> heroes in A-Z</li>
<li>Has <span id='points_total'>0</span> doobs points</li>
<li>Last seen at <span class='date'> {{ user.last_seen | js_datetime }}</span></li>
<li>Doob since <span class='date'> {{ user.created | js_datetime }}</span></li>

19
app/templates/profile.html

@ -45,19 +45,6 @@
<!-- Side bar -->
<div class="uk-width-large-1-3 uk-width-medium-1-1 uk-panel">
{% if user.public %}
<div class="uk-container-center uk-text-center">
<span class="uk-text-bold">Current Hero</span><br/>
<span class="uk-text-success uk-text-bold">
{{ user.random_hero['localized_name'] }}
({{ user.random_heroes.completed | length + 1 }}
/
{{ total_hero_pool() - user.random_heroes.completed|length }})
</span><br/>
<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>
<table class="uk-table uk-table-hover uk-table-condensed">
<caption>{{ user.nickname }}</caption>
<tbody class="uk-text-small">
@ -83,12 +70,6 @@
</tr>
</tbody>
</table>
{% if not user.winrate_data['data'] %}
<h3 class="uk-text-warning">No data compiled, check back tomorrow!</h3>
<button class="uk-button uk-button-success uk-align-center" data-uk-modal="{target: '#winrate_modal'}" disabled>View Winrate</button>
{% else %}
<button class="uk-button uk-button-success uk-align-center" data-uk-modal="{target: '#winrate_modal'}">View Winrate</button>
{% endif %}
{% endif %}
</div>
</div>

18
app/views.py

@ -56,7 +56,7 @@ def create_or_login(resp):
match = app.config['STEAM_ID_RE'].search(resp.identity_url)
g.user = User.get_or_create(match.group(1))
steamdata = get_steam_userinfo(g.user.steam_id)
g.user.nickname = steamdata['personaname']
g.user.nickname = steamdata['personaname'].encode('utf-8', 'replace')
g.user.avatar = steamdata['avatar']
db.session.commit()
session['user_id'] = g.user.id
@ -80,28 +80,12 @@ def teamspeak():
def friends():
return render_template('friends.html')
# Stream pages
@app.route('/shaneomad')
def twitch_shaneomad():
return render_template('potatr.html', twitch_id=app.config.TWITCH_CLIENT_ID)
# User profile page
@app.route('/user/<int:userid>')
def user_profile(userid):
user = User.query.filter_by(id=userid).first_or_404()
return render_template('profile.html', user=user)
# User random a-z challenge progress page
@app.route('/user/<int:userid>/random', methods=['POST', 'GET'])
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)
# User settings page
@app.route('/settings', methods=['POST', 'GET'])
@login_required

34
migrations/versions/50e77b6e7331_.py

@ -0,0 +1,34 @@
"""empty message
Revision ID: 50e77b6e7331
Revises: 9e520de441f
Create Date: 2014-11-17 13:21:23.705195
"""
# revision identifiers, used by Alembic.
revision = '50e77b6e7331'
down_revision = '9e520de441f'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.add_column('user', sa.Column('ts3_longest_stretch', sa.Interval(), nullable=True))
op.add_column('user', sa.Column('ts3_stretch_award_time', sa.DateTime(), nullable=True))
op.drop_column('user', u'random_heroes')
op.drop_column('user', u'ts3_connections')
op.drop_column('user', u'az_completions')
### end Alembic commands ###
def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.add_column('user', sa.Column(u'az_completions', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True))
op.add_column('user', sa.Column(u'ts3_connections', mysql.TEXT(), nullable=True))
op.add_column('user', sa.Column(u'random_heroes', mysql.TEXT(), nullable=True))
op.drop_column('user', 'ts3_stretch_award_time')
op.drop_column('user', 'ts3_longest_stretch')
### end Alembic commands ###

5
requirements.txt

@ -9,7 +9,7 @@ Flask-WTF==0.9.4
Jinja2==2.7.1
Mako==1.0.0
MarkupSafe==0.18
MySQL-python==1.2.4
MySQL-python==1.2.5
Pygments==1.6
SQLAlchemy==0.8.4
WTForms==1.0.5
@ -24,13 +24,12 @@ ipdb==0.8
ipython==2.1.0
itsdangerous==0.23
nose==1.3.3
numpy==1.8.1
peewee==2.1.6
pyparsing==2.0.2
python-crontab==1.8.1
python-dateutil==2.2
python-openid==2.2.5
python-ts3==0.1
#python-ts3==0.1
pytz==2014.4
requests==2.1.0
simplejson==3.3.1

14
run.py

@ -57,7 +57,15 @@ def install_cronjobs():
print "Problem installing cronjobs: {}".format(e)
else:
cron.write()
print "Cron jobs written succesfully"
print "Cron jobs written successfully"
@manager.command
def delete_cronjobs():
from os import path
from crontab import CronTab
cron = CronTab(user=True)
cron.remove_all(comment='DOOBSAUTO')
print "Existing cronjobs deleted successfully"
@manager.command
def admin(name):
@ -96,6 +104,10 @@ def ts3_process_events():
tsServer = createTeamspeakInstance()
process_ts3_events(tsServer)
@manager.command
def forum_award_points():
for user in models.User.query.filter(models.User.forum_id != None).all():
user.update_forum_posts()
if __name__ == '__main__':
manager.run()
Loading…
Cancel
Save