initial commit - porting over
230
__init__.py
Normal file
@ -0,0 +1,230 @@
|
||||
from flask import Flask
|
||||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from flask.ext.openid import OpenID
|
||||
from flask.ext.cache import Cache
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object('config')
|
||||
db = SQLAlchemy(app)
|
||||
oid = OpenID(app)
|
||||
cache = Cache(app, config={'CACHE_TYPE': app.config['CACHE_TYPE']})
|
||||
|
||||
from app import views
|
||||
|
||||
'''
|
||||
from flask import Flask, render_template
|
||||
from flask.ext.mongoengine import MongoEngine
|
||||
from flask.ext.openid import OpenID
|
||||
from flask.ext.cache import Cache
|
||||
import utils
|
||||
import ts3
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object('config')
|
||||
|
||||
#Setup mongo database
|
||||
db = MongoEngine(app)
|
||||
|
||||
#Setup OpenID and Caching
|
||||
oid = OpenID(app)
|
||||
cache = Cache(app, config={'CACHE_TYPE': app.config['CACHE_TYPE']})
|
||||
|
||||
from app import views
|
||||
@app.route('/')
|
||||
def inx():
|
||||
return render_template('main.html')
|
||||
|
||||
##### INTO UTILS LATER #####
|
||||
RADIANT_TEAM = 2
|
||||
DIRE_TEAM = 3
|
||||
RADIANT_COLOR = 'b'
|
||||
DIRE_COLOR = 'r'
|
||||
|
||||
def get_hero_data():
|
||||
xhr = urllib2.build_opener().open(urllib2.Request("https://api.steampowered.com/IEconDOTA2_570/GETHeroes/v0001/?key="+DOTA2_API_KEY+"&language=en_us"))
|
||||
data = json.load(xhr)
|
||||
return data
|
||||
|
||||
@app.context_processor
|
||||
def utility_processor():
|
||||
@cache.memoize(60*5)
|
||||
def ts3_viewer():
|
||||
try:
|
||||
server = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT'])
|
||||
server.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD'])
|
||||
server.use(1)
|
||||
|
||||
serverinfo = server.send_command('serverinfo').data
|
||||
channellist = server.send_command('channellist', opts=("limits", "flags", "voice", "icon")).data
|
||||
clientlist = server.send_command('clientlist', opts=("away", "voice", "info", "icon", "groups", "country")).data
|
||||
servergrouplist = server.send_command('servergrouplist').data
|
||||
channelgrouplist = server.send_command('channelgrouplist').data
|
||||
|
||||
soup = BeautifulSoup()
|
||||
div_tag = soup.new_tag('div')
|
||||
div_tag['class'] ='devmx-webviewer'
|
||||
soup.append(div_tag)
|
||||
|
||||
def construct_channels(parent_tag, cid):
|
||||
num_clients = 0
|
||||
for channel in channellist:
|
||||
if int(channel['pid']) == int(cid):
|
||||
# Construct the channel
|
||||
channel_tag = soup.new_tag('div')
|
||||
channel_tag['class'] = 'tswv-channel'
|
||||
# Channel image
|
||||
image_tag = soup.new_tag('span')
|
||||
image_tag['class'] = 'tswv-image tswv-image-right'
|
||||
if int(channel['channel_flag_password']) == 1:
|
||||
image_tag['class'] += ' tswv-channel-password-right'
|
||||
if int(channel['channel_flag_default']) == 1:
|
||||
image_tag['class'] += ' tswv-channel-home'
|
||||
if int(channel['channel_needed_talk_power']) > 0:
|
||||
image_tag['class'] += ' tswv-channel-moderated'
|
||||
if int(channel['channel_icon_id']) != 0:
|
||||
raise NotImplementedError
|
||||
image_tag.append(' ')
|
||||
channel_tag.append(image_tag)
|
||||
# Status image
|
||||
status_tag = soup.new_tag('span')
|
||||
status_tag['class'] = 'tswv-image'
|
||||
if int(channel['channel_flag_password']) == 1:
|
||||
status_tag['class'] += ' tswv-channel-password'
|
||||
elif int(channel['total_clients']) == int(channel['channel_maxclients']):
|
||||
status_tag['class'] += ' tswv-channel-full'
|
||||
else:
|
||||
status_tag['class'] += ' tswv-channel-normal'
|
||||
status_tag.append(' ')
|
||||
channel_tag.append(status_tag)
|
||||
# Label
|
||||
label_tag = soup.new_tag('span')
|
||||
label_tag['class'] = 'tswv-label'
|
||||
label_tag.append(channel['channel_name'])
|
||||
channel_tag.append(label_tag)
|
||||
# Clients
|
||||
channel_tag, channel_clients = construct_clients(channel_tag, channel['cid'])
|
||||
# Recurse through sub-channels, collecting total number of clients as we go
|
||||
channel_tag, sub_clients = construct_channels(channel_tag, channel['cid'])
|
||||
channel_clients += sub_clients
|
||||
# Only show non-empty channels
|
||||
if channel_clients > 0:
|
||||
parent_tag.append(channel_tag)
|
||||
num_clients += channel_clients
|
||||
return parent_tag, num_clients
|
||||
|
||||
def construct_clients(parent_tag, cid):
|
||||
num_clients = 0
|
||||
for client in clientlist:
|
||||
if int(client['cid']) == int(cid):
|
||||
# Skip ServerQuery clients
|
||||
if int(client['client_type']) == 1: continue
|
||||
num_clients += 1
|
||||
client_tag = soup.new_tag('div')
|
||||
client_tag['class'] = 'tswv-client'
|
||||
# Status image
|
||||
status_tag = soup.new_tag('span')
|
||||
status_tag['class'] = 'tswv-image'
|
||||
if int(client['client_type']) == 1:
|
||||
status_tag['class'] += ' tswv-client-query'
|
||||
elif int(client['client_away']) == 1:
|
||||
status_tag['class'] += " tswv-client-away"
|
||||
elif int(client['client_input_muted']) == 1:
|
||||
status_tag['class'] += " tswv-client-input-muted"
|
||||
elif int(client['client_output_muted']) == 1:
|
||||
status_tag['class'] += " tswv-client-output-muted"
|
||||
elif int(client['client_input_hardware']) == 0:
|
||||
status_tag['class'] += " tswv-client-input-muted-hardware"
|
||||
elif int(client['client_output_hardware']) == 0:
|
||||
status_tag['class'] += " tswv-client-output-muted-hardware"
|
||||
elif (int(client['client_flag_talking']) == 1) and (int(client['client_is_channel_commander']) == 1):
|
||||
status_tag['class'] += " tswv-client-channel-commander-talking"
|
||||
elif int(client['client_is_channel_commander']) == 1:
|
||||
status_tag['class'] += " tswv-client-channel-commander"
|
||||
elif int(client['client_flag_talking']) == 1:
|
||||
status_tag['class'] += " tswv-client-talking"
|
||||
else:
|
||||
status_tag['class'] += " tswv-client-normal"
|
||||
status_tag.append(' ')
|
||||
client_tag.append(status_tag)
|
||||
# Country image
|
||||
country_tag = soup.new_tag('span')
|
||||
country_tag['class'] = 'tswv-image tswv-image-right'
|
||||
country_tag['title'] = ' '.join([word.capitalize() for word in utils.ISO3166_MAPPING[client['client_country']].split(' ')])
|
||||
country_tag['style'] = 'background: url("%s") center center no-repeat;' % url_for('static', filename='img/ts3_viewer/countries/%s.png' % client['client_country'].lower())
|
||||
country_tag.append(' ')
|
||||
client_tag.append(country_tag)
|
||||
# Server group images
|
||||
sgids = [int(sg) for sg in client['client_servergroups'].split(',')]
|
||||
servergroups = [servergroup for servergroup in servergrouplist if int(servergroup['sgid']) in sgids]
|
||||
servergroups.sort(key=operator.itemgetter('sortid'))
|
||||
for servergroup in servergroups:
|
||||
if not servergroup['iconid']: continue
|
||||
img_fname = 'img/ts3_viewer/%s.png' % servergroup['iconid']
|
||||
if not os.path.exists(os.path.join(app.static_folder, img_fname)):
|
||||
continue
|
||||
image_tag = soup.new_tag('span')
|
||||
image_tag['class'] = 'tswv-image tswv-image-right'
|
||||
image_tag['title'] = servergroup['name']
|
||||
image_tag['style'] = 'background-image: url("%s")' % url_for('static', filename=img_fname)
|
||||
image_tag.append(' ')
|
||||
client_tag.append(image_tag)
|
||||
# Check if client is in a moderated channel
|
||||
channel = [channel for channel in channellist if int(channel['cid']) == int(client['cid'])][0]
|
||||
if int(channel['channel_needed_talk_power']) > 0:
|
||||
status_tag = soup.new_tag('span')
|
||||
status_tag['class'] = 'tswv-image tswv-image-right'
|
||||
if int(client['client_is_talker']) == 0:
|
||||
status_tag['class'] += ' tswv-client-input-muted'
|
||||
else:
|
||||
status_tag['class'] += ' tswv-client-talkpower-granted'
|
||||
status_tag.append(' ')
|
||||
client_tag.append(status_tag)
|
||||
# Label
|
||||
label_tag = soup.new_tag('span')
|
||||
label_tag['class'] = 'tswv-label'
|
||||
label_tag.append(client['client_nickname'])
|
||||
client_tag.append(label_tag)
|
||||
parent_tag.append(client_tag)
|
||||
return parent_tag, num_clients
|
||||
div_tag, num_clients = construct_channels(div_tag, 0)
|
||||
return soup.prettify()
|
||||
except Exception as inst:
|
||||
return "error: %s" % inst
|
||||
def shorten_text(text, num_words=10):
|
||||
text = utils.fix_bad_unicode(text)
|
||||
space_iter = re.finditer('\s+', text)
|
||||
output = u''
|
||||
while num_words > 0:
|
||||
match = space_iter.next()
|
||||
if not match: break
|
||||
output = text[:match.end()]
|
||||
num_words -= 1
|
||||
else:
|
||||
output += '...'
|
||||
return output
|
||||
def num_unique_clients(teamspeak_data):
|
||||
unique_clients = set()
|
||||
for data in teamspeak_data:
|
||||
unique_clients.update(data.clients)
|
||||
return len(unique_clients)
|
||||
def num_unique_clients_by_country(teamspeak_data):
|
||||
unique_clients = {}
|
||||
for data in teamspeak_data:
|
||||
for client_id, client_data in data.clients.iteritems():
|
||||
unique_clients[client_id] = (client_data['country'] or 'Unknown').lower()
|
||||
country = {}
|
||||
for client_id, country_code in unique_clients.iteritems():
|
||||
country[country_code] = country.get(country_code, 0) + 1
|
||||
return country
|
||||
def country_abbreviation_mapping():
|
||||
mapping = {}
|
||||
for key, name in utils.ISO3166_MAPPING.iteritems():
|
||||
mapping[key.lower()] = ' '.join([word.capitalize() for word in name.split(' ')])
|
||||
return mapping
|
||||
return dict(timestamp_to_js_date=utils.timestamp_to_js_date, ts3_viewer=ts3_viewer, shorten_text=shorten_text, getTeamspeakWindow=doob.getTeamspeakWindow,
|
||||
num_unique_clients=num_unique_clients,
|
||||
num_unique_clients_by_country=num_unique_clients_by_country,
|
||||
country_abbreviation_mapping=country_abbreviation_mapping)
|
||||
|
||||
|
||||
'''
|
BIN
__init__.pyc
Normal file
469
board.py
Normal file
@ -0,0 +1,469 @@
|
||||
import os
|
||||
from time import strftime, gmtime
|
||||
from peewee import *
|
||||
from app import app, cache
|
||||
|
||||
db = MySQLDatabase(app.config['FORUM_NAME'], **{'passwd': app.config['FORUM_PASSWORD'],
|
||||
'host': app.config['FORUM_HOST'], 'user': app.config['FORUM_USERNAME']})
|
||||
|
||||
@cache.memoize(60*5)
|
||||
def latest_news(num=2):
|
||||
latest_news = []
|
||||
try:
|
||||
db.connect()
|
||||
news_forum = Forums.get(fn.Lower(Forums.title) % '%news%')
|
||||
for thread in Threads.select().where(
|
||||
Threads.forum == news_forum.id).order_by(Threads.date).limit(num):
|
||||
# Last revision of the first post
|
||||
post = Posts.select().where(Posts.thread == thread.id).get()
|
||||
text = PostsText.select().where(PostsText.pid == post.id).order_by(PostsText.revision.desc()).limit(1).get()
|
||||
timestamp = thread.date
|
||||
date = strftime('%B %d, %Y %H:%M:%S UTC', gmtime(timestamp))
|
||||
if not date:
|
||||
post = Posts.select().where(Posts.thread == thread.id).get()
|
||||
date = post and post.date
|
||||
url = 'http://board.dotanoobs.com/?page=thread&id=%d' % thread.id
|
||||
latest_news.append({'title':thread.title, 'text':text.text, 'date':date, 'timestamp':timestamp, 'url':url})
|
||||
except Exception as e:
|
||||
latest_news.append({'title':'Error with forum db', 'text':e, 'url':''})
|
||||
finally:
|
||||
db.close()
|
||||
return latest_news
|
||||
|
||||
class UnknownFieldType(object):
|
||||
pass
|
||||
|
||||
class BaseModel(Model):
|
||||
class Meta:
|
||||
database = db
|
||||
|
||||
class Badges(BaseModel):
|
||||
color = IntegerField()
|
||||
name = CharField()
|
||||
owner = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'badges'
|
||||
|
||||
class Blockedlayouts(BaseModel):
|
||||
blockee = IntegerField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'blockedlayouts'
|
||||
|
||||
class Categories(BaseModel):
|
||||
corder = IntegerField()
|
||||
name = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'categories'
|
||||
|
||||
class Enabledplugins(BaseModel):
|
||||
plugin = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'enabledplugins'
|
||||
|
||||
class Forummods(BaseModel):
|
||||
forum = IntegerField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'forummods'
|
||||
|
||||
class Forums(BaseModel):
|
||||
catid = IntegerField()
|
||||
description = TextField(null=True)
|
||||
forder = IntegerField()
|
||||
hidden = IntegerField()
|
||||
lastpostdate = IntegerField()
|
||||
lastpostid = IntegerField()
|
||||
lastpostuser = IntegerField()
|
||||
minpower = IntegerField()
|
||||
minpowerreply = IntegerField()
|
||||
minpowerthread = IntegerField()
|
||||
numposts = IntegerField()
|
||||
numthreads = IntegerField()
|
||||
title = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'forums'
|
||||
|
||||
class Guests(BaseModel):
|
||||
bot = IntegerField()
|
||||
date = IntegerField()
|
||||
ip = CharField()
|
||||
lastforum = IntegerField()
|
||||
lasturl = CharField()
|
||||
useragent = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'guests'
|
||||
|
||||
class Ignoredforums(BaseModel):
|
||||
fid = IntegerField()
|
||||
uid = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'ignoredforums'
|
||||
|
||||
class Ip2C(BaseModel):
|
||||
cc = CharField(null=True)
|
||||
ip_from = BigIntegerField()
|
||||
ip_to = BigIntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'ip2c'
|
||||
|
||||
class Ipbans(BaseModel):
|
||||
date = IntegerField()
|
||||
ip = CharField()
|
||||
reason = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'ipbans'
|
||||
|
||||
class Log(BaseModel):
|
||||
date = IntegerField()
|
||||
forum = IntegerField()
|
||||
forum2 = IntegerField()
|
||||
ip = CharField()
|
||||
pm = IntegerField()
|
||||
post = IntegerField()
|
||||
text = CharField()
|
||||
thread = IntegerField()
|
||||
type = CharField()
|
||||
user = IntegerField()
|
||||
user2 = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'log'
|
||||
|
||||
class Misc(BaseModel):
|
||||
hotcount = IntegerField()
|
||||
maxpostsday = IntegerField()
|
||||
maxpostsdaydate = IntegerField()
|
||||
maxpostshour = IntegerField()
|
||||
maxpostshourdate = IntegerField()
|
||||
maxusers = IntegerField()
|
||||
maxusersdate = IntegerField()
|
||||
maxuserstext = TextField(null=True)
|
||||
milestone = TextField(null=True)
|
||||
version = IntegerField()
|
||||
views = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'misc'
|
||||
|
||||
class Moodavatars(BaseModel):
|
||||
mid = IntegerField()
|
||||
name = CharField()
|
||||
uid = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'moodavatars'
|
||||
|
||||
class Notifications(BaseModel):
|
||||
description = TextField(null=True)
|
||||
link = IntegerField()
|
||||
linklocation = CharField()
|
||||
time = IntegerField()
|
||||
title = CharField()
|
||||
type = CharField()
|
||||
uid = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'notifications'
|
||||
|
||||
class Pmsgs(BaseModel):
|
||||
date = IntegerField()
|
||||
deleted = IntegerField()
|
||||
drafting = IntegerField()
|
||||
ip = CharField()
|
||||
msgread = IntegerField()
|
||||
userfrom = IntegerField()
|
||||
userto = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'pmsgs'
|
||||
|
||||
class PmsgsText(BaseModel):
|
||||
pid = IntegerField()
|
||||
text = TextField(null=True)
|
||||
title = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'pmsgs_text'
|
||||
|
||||
class Poll(BaseModel):
|
||||
briefing = TextField(null=True)
|
||||
closed = IntegerField()
|
||||
doublevote = IntegerField()
|
||||
question = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'poll'
|
||||
|
||||
class PollChoices(BaseModel):
|
||||
choice = CharField()
|
||||
color = CharField()
|
||||
poll = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'poll_choices'
|
||||
|
||||
class Pollvotes(BaseModel):
|
||||
choiceid = IntegerField()
|
||||
poll = IntegerField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'pollvotes'
|
||||
|
||||
class Postplusones(BaseModel):
|
||||
post = IntegerField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'postplusones'
|
||||
|
||||
class Posts(BaseModel):
|
||||
currentrevision = IntegerField()
|
||||
date = IntegerField()
|
||||
deleted = IntegerField()
|
||||
deletedby = IntegerField()
|
||||
ip = CharField()
|
||||
mood = IntegerField()
|
||||
num = IntegerField()
|
||||
options = IntegerField()
|
||||
postplusones = IntegerField()
|
||||
reason = CharField()
|
||||
thread = IntegerField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'posts'
|
||||
|
||||
class PostsText(BaseModel):
|
||||
date = IntegerField()
|
||||
pid = IntegerField(primary_key=True)
|
||||
revision = IntegerField()
|
||||
text = TextField(null=True)
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'posts_text'
|
||||
|
||||
class Proxybans(BaseModel):
|
||||
ip = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'proxybans'
|
||||
|
||||
class Queryerrors(BaseModel):
|
||||
cookie = TextField(null=True)
|
||||
error = TextField(null=True)
|
||||
get = TextField(null=True)
|
||||
ip = CharField()
|
||||
post = TextField(null=True)
|
||||
query = TextField(null=True)
|
||||
time = IntegerField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'queryerrors'
|
||||
|
||||
class Reports(BaseModel):
|
||||
hidden = IntegerField()
|
||||
ip = CharField()
|
||||
request = TextField(null=True)
|
||||
severity = IntegerField()
|
||||
text = CharField()
|
||||
time = IntegerField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'reports'
|
||||
|
||||
class Sessions(BaseModel):
|
||||
autoexpire = IntegerField()
|
||||
expiration = IntegerField()
|
||||
id = CharField()
|
||||
iplock = IntegerField()
|
||||
iplockaddr = CharField()
|
||||
lastip = CharField()
|
||||
lasttime = IntegerField()
|
||||
lasturl = CharField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'sessions'
|
||||
|
||||
class Settings(BaseModel):
|
||||
name = CharField()
|
||||
plugin = CharField()
|
||||
value = TextField(null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'settings'
|
||||
|
||||
class Smilies(BaseModel):
|
||||
code = CharField()
|
||||
image = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'smilies'
|
||||
|
||||
class Threads(BaseModel):
|
||||
closed = IntegerField()
|
||||
date = IntegerField()
|
||||
firstpostid = IntegerField()
|
||||
forum = IntegerField()
|
||||
icon = CharField()
|
||||
lastpostdate = IntegerField()
|
||||
lastposter = IntegerField()
|
||||
lastpostid = IntegerField()
|
||||
poll = IntegerField()
|
||||
replies = IntegerField()
|
||||
sticky = IntegerField()
|
||||
title = CharField()
|
||||
user = IntegerField()
|
||||
views = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'threads'
|
||||
|
||||
class Threadsread(BaseModel):
|
||||
date = IntegerField()
|
||||
thread = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'threadsread'
|
||||
|
||||
class Uploader(BaseModel):
|
||||
category = IntegerField()
|
||||
date = IntegerField()
|
||||
description = CharField()
|
||||
downloads = IntegerField()
|
||||
filename = CharField()
|
||||
private = IntegerField()
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'uploader'
|
||||
|
||||
class UploaderCategories(BaseModel):
|
||||
description = TextField(null=True)
|
||||
name = CharField()
|
||||
ord = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'uploader_categories'
|
||||
|
||||
class Usercomments(BaseModel):
|
||||
cid = IntegerField()
|
||||
date = IntegerField()
|
||||
text = TextField(null=True)
|
||||
uid = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'usercomments'
|
||||
|
||||
class Usergroups(BaseModel):
|
||||
inherits = IntegerField()
|
||||
permissions = TextField(null=True)
|
||||
title = CharField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'usergroups'
|
||||
|
||||
class Userpermissions(BaseModel):
|
||||
permissions = TextField(null=True)
|
||||
uid = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'userpermissions'
|
||||
|
||||
class Users(BaseModel):
|
||||
bio = TextField(null=True)
|
||||
birthday = IntegerField()
|
||||
blocklayouts = IntegerField()
|
||||
color = CharField()
|
||||
dateformat = CharField()
|
||||
displayname = CharField()
|
||||
email = CharField()
|
||||
fontsize = IntegerField()
|
||||
forbiddens = CharField()
|
||||
globalblock = IntegerField()
|
||||
hascolor = IntegerField()
|
||||
homepagename = CharField()
|
||||
homepageurl = CharField()
|
||||
karma = IntegerField()
|
||||
lastactivity = IntegerField()
|
||||
lastforum = IntegerField()
|
||||
lastip = CharField()
|
||||
lastknownbrowser = TextField(null=True)
|
||||
lastposttime = IntegerField()
|
||||
lasturl = CharField()
|
||||
location = CharField()
|
||||
loggedin = IntegerField()
|
||||
lostkey = CharField()
|
||||
lostkeytimer = IntegerField()
|
||||
minipic = CharField()
|
||||
name = CharField()
|
||||
newcomments = IntegerField()
|
||||
password = CharField()
|
||||
picture = CharField()
|
||||
pluginsettings = TextField(null=True)
|
||||
postheader = TextField(null=True)
|
||||
postplusones = IntegerField()
|
||||
postplusonesgiven = IntegerField()
|
||||
posts = IntegerField()
|
||||
postsperpage = IntegerField()
|
||||
powerlevel = IntegerField()
|
||||
pss = CharField()
|
||||
rankset = CharField()
|
||||
realname = CharField()
|
||||
regdate = IntegerField()
|
||||
sex = IntegerField()
|
||||
showemail = IntegerField()
|
||||
signature = TextField(null=True)
|
||||
signsep = IntegerField()
|
||||
tempbanpl = IntegerField()
|
||||
tempbantime = BigIntegerField()
|
||||
theme = CharField()
|
||||
threadsperpage = IntegerField()
|
||||
timeformat = CharField()
|
||||
timezone = FloatField()
|
||||
title = CharField()
|
||||
usebanners = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'users'
|
||||
|
||||
class Uservotes(BaseModel):
|
||||
uid = IntegerField()
|
||||
up = IntegerField()
|
||||
voter = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'uservotes'
|
||||
|
||||
class WikiPages(BaseModel):
|
||||
flags = IntegerField()
|
||||
id = CharField()
|
||||
revision = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'wiki_pages'
|
||||
|
||||
class WikiPagesText(BaseModel):
|
||||
date = IntegerField()
|
||||
id = CharField()
|
||||
revision = IntegerField()
|
||||
text = TextField(null=True)
|
||||
user = IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = 'wiki_pages_text'
|
20
models.py
Normal file
@ -0,0 +1,20 @@
|
||||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from app import db
|
||||
|
||||
class User(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
steam_id = db.Column(db.String(40), unique=True)
|
||||
nickname = db.Column(db.String(80))
|
||||
avatar = db.Column(db.String(255))
|
||||
|
||||
@staticmethod
|
||||
def get_or_create(steam_id):
|
||||
rv = User.query.filter_by(steam_id=steam_id).first()
|
||||
if rv is None:
|
||||
rv = User()
|
||||
rv.steam_id = steam_id
|
||||
db.session.add(rv)
|
||||
return rv
|
||||
|
||||
def __repr__(self):
|
||||
return '<User {}>'.format(self.steam_id)
|
BIN
models.pyc
Normal file
56
static/css/app.css
Normal file
@ -0,0 +1,56 @@
|
||||
body {
|
||||
/*background:url("../img/back_pattern.png") repeat fixed 0 0 transparent;*/
|
||||
}
|
||||
#container {
|
||||
width: 80%;
|
||||
margin: 1em auto 6em;
|
||||
}
|
||||
#biglogo {
|
||||
width:75%;
|
||||
}
|
||||
.dark-panel {
|
||||
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 {
|
||||
height:35px;
|
||||
}
|
||||
|
||||
footer {
|
||||
width:60%;
|
||||
text-align:center;
|
||||
border-top: 1px solid #999;
|
||||
padding:8px 30px;
|
||||
}
|
||||
|
||||
#ocnav-header {
|
||||
padding-left:22%;
|
||||
color: white;
|
||||
}
|
||||
.uk-nav-side > li.uk-active > a {
|
||||
background-color: #6FAC34;
|
||||
}
|
||||
|
||||
.dn-news-article > .uk-article-title {
|
||||
font-size:26px;
|
||||
}
|
||||
.dn-news-article > .uk-article-title:hover {
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
#about-us-more, #less {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.team_logo {
|
||||
border-radius:6px;
|
||||
margin-right: 1em;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.25);
|
||||
}
|
||||
|
||||
.botpad {
|
||||
padding-bottom:80px;
|
||||
}
|
45
static/css/heropedia.css
Normal file
@ -0,0 +1,45 @@
|
||||
.uk-panel.tavern {
|
||||
border-left: 2px solid #CCCCCC;
|
||||
display: inline-block;
|
||||
padding: 2px;
|
||||
}
|
||||
.uk-panel.tavern > img {
|
||||
padding:4px;
|
||||
margin:2px;
|
||||
}
|
||||
#tavernStrength, #tavernAgility, #tavernIntelligence {
|
||||
display:block;
|
||||
background-image:url('http://media.steampowered.com/apps/dota2/images/heropedia/overviewicon_str.png');
|
||||
background-repeat:no-repeat;
|
||||
overflow:visible;
|
||||
text-transform:uppercase;
|
||||
color: rgba(105,211,50,0.75);
|
||||
padding:6px 10px 15px 40px;
|
||||
}
|
||||
#tavernAgility{
|
||||
background-image:url('http://media.steampowered.com/apps/dota2/images/heropedia/overviewicon_agi.png');
|
||||
}
|
||||
#tavernIntelligence{
|
||||
background-image:url('http://media.steampowered.com/apps/dota2/images/heropedia/overviewicon_int.png');
|
||||
}
|
||||
|
||||
.heroIcons {
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.heroCol {
|
||||
float:left;
|
||||
width:277px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.filterMatchedHero {
|
||||
background-color:#000;
|
||||
}
|
||||
.filterUnmatchedHero {
|
||||
filter:alpha(opacity=25);
|
||||
-moz-opacity: .25;
|
||||
opacity: .25;
|
||||
background-color:#000000;
|
||||
cursor:default;
|
||||
}
|
3
static/css/uikit.almost-flat.min.css
vendored
Normal file
3
static/css/uikit.gradient.min.css
vendored
Normal file
3
static/css/uikit.min.css
vendored
Normal file
BIN
static/fonts/FontAwesome.otf
Normal file
BIN
static/fonts/fontawesome-webfont.eot
Normal file
BIN
static/fonts/fontawesome-webfont.ttf
Normal file
BIN
static/fonts/fontawesome-webfont.woff
Normal file
BIN
static/img/asc.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
static/img/back_pattern.png
Normal file
After Width: | Height: | Size: 424 B |
BIN
static/img/bg.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
static/img/biglogo.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
static/img/desc.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
static/img/email.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
static/img/hero-images/abaddon_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/alchemist_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/ancient_apparition_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/antimage.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/antimage_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/axe_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/bane_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/batrider.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
static/img/hero-images/batrider_small.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
static/img/hero-images/beastmaster_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/bloodseeker_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/bounty_hunter.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
static/img/hero-images/bounty_hunter_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/brewmaster_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/bristleback_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/broodmother_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/centaur_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/chaos_knight.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
static/img/hero-images/chaos_knight_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/chen_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/clinkz.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
static/img/hero-images/clinkz_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/crystal_maiden_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/dark_seer.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
static/img/hero-images/dark_seer_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/dazzle_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/death_prophet_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/disruptor.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
static/img/hero-images/disruptor_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/doom_bringer_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/dragon_knight_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/drow_ranger_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/earthshaker_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/elder_titan_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/enchantress_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/enigma_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/faceless_void.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/faceless_void_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/furion.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/furion_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/gyrocopter.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/gyrocopter_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/huskar.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
static/img/hero-images/huskar_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/invoker.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
static/img/hero-images/invoker_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/jakiro.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
static/img/hero-images/jakiro_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/juggernaut_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/keeper_of_the_light.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/keeper_of_the_light_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/kunkka.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/kunkka_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/leshrac_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/lich.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
static/img/hero-images/lich_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/life_stealer.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/life_stealer_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/lina.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/lina_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/lion_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/lone_druid.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
static/img/hero-images/lone_druid_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/luna.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
static/img/hero-images/luna_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/lycan_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/magnataur.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/img/hero-images/magnataur_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/medusa_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/meepo_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/mirana_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/morphling_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/naga_siren_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/necrolyte_small.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/img/hero-images/nevermore_small.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
static/img/hero-images/night_stalker_small.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/img/hero-images/nyx_assassin.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
static/img/hero-images/nyx_assassin_small.png
Normal file
After Width: | Height: | Size: 10 KiB |