Compare commits

...
This repository has been archived on 2025-01-27. You can view files and clone it, but cannot push or open issues or pull requests.

34 commits
master ... v0.1

Author SHA1 Message Date
1a0040626f clear 2018-01-15 13:19:02 +03:00
vanzhiganov
acc2547aa0 fix sort 2018-01-13 15:42:38 +03:00
vanzhiganov
e8d1b13245 Merge branch 'v0.1' of ssh://9redmine.com/wtstts/wots-server into v0.1 2018-01-13 13:14:36 +03:00
vanzhiganov
726a2de927 fix sort 2018-01-13 13:13:28 +03:00
d6334bde4e up 2017-12-25 14:57:49 +03:00
9237ad9793 up 2017-12-25 14:53:54 +03:00
vanzhiganov
2688960be3 upd 2017-12-25 04:09:03 +03:00
vanzhiganov
4d68d3d457 fix secret key 2017-12-16 17:25:23 +03:00
vanzhiganov
cfb7258d24 fix sort 2017-12-16 16:40:33 +03:00
vanzhiganov
4dcf7d63c3 fix 2017-12-11 05:14:18 +03:00
vanzhiganov
d7b33085ff update 2017-11-06 19:49:00 +03:00
vanzhiganov
d4e996b33b update 2017-10-30 01:29:42 +03:00
vanzhiganov
b6f8d378c8 upgrade 2017-10-29 17:31:48 +03:00
e60a90754d update 2017-10-25 04:09:30 +03:00
f07aba34c8 update 2017-10-25 04:02:55 +03:00
944028c9d0 update 2017-10-25 03:38:25 +03:00
52cecf2ecf update 2017-10-23 03:15:56 +03:00
79a71f20da update 2017-10-23 03:14:41 +03:00
f63ef1dcc0 update 2017-10-23 03:12:18 +03:00
9a2529bc4d update 2017-10-23 03:12:09 +03:00
dfb7f1288e update 2017-10-23 02:41:54 +03:00
a8b73c3ad5 update 2017-10-20 05:37:51 +03:00
3aa9ce6065 add migration 2017-10-20 05:19:07 +03:00
d39ab585a9 remove alembic folder 2017-10-20 03:31:15 +03:00
ab02598a32 rush add 2017-10-20 03:29:57 +03:00
vanzhiganov
d49f0a3038 add rush page 2017-10-14 20:45:17 +03:00
vanzhiganov
aeba81ed99 add new information technic and anchive 2017-09-30 20:22:30 +03:00
vanzhiganov
a9040ec080 add new information technic and anchive 2017-09-30 10:42:23 +03:00
vanzhiganov
4f0fc666ec add new information technic and anchive 2017-09-30 09:34:17 +03:00
vanzhiganov
7e2883bd03 fix 2017-09-22 00:20:22 +03:00
vanzhiganov
9c2398bc40 remove celerybeat-schedule 2017-09-21 23:57:01 +03:00
7a5fea1913 optimize 2017-09-21 13:16:04 +03:00
1b4627bb88 optimize 2017-09-21 12:05:21 +03:00
c677f6459c comment unused code 2017-09-21 11:47:05 +03:00
59 changed files with 11197 additions and 263 deletions

2
.gitignore vendored
View file

@ -3,3 +3,5 @@
celerybeat-schendule celerybeat-schendule
tmp/associations/ tmp/associations/
tmp/nonces/ tmp/nonces/
celerybeat.pid
celerybeat-schedule

View file

@ -9,33 +9,28 @@
## Install ## Install
For postgres installation For Postgres installation
https://developer.fedoraproject.org/tech/database/postgresql/about.html https://developer.fedoraproject.org/tech/database/postgresql/about.html
pip install -r requirements.txt
`````` ## Upgrade
``` Upgrade database
pip install -r requirements.txt
```
### Run python manage.py db upgrade head
## Run
Application Application
``` python run_app.py
python run_app.py
```
Celery Worker Celery Worker
``` celery worker -A run_celery.celery -l info
celery worker -A run_celery.celery -l info
```
Celery Beat Celery Beat
``` celery beat -A run_celery.celery -l debug
celery beat -A run_celery.celery -l debug
```

View file

@ -1 +0,0 @@
Generic single-database configuration.

View file

@ -1,71 +0,0 @@
from __future__ import with_statement
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig
# from wotstats.database import db
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = None
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=target_metadata, literal_binds=True)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

View file

@ -1,24 +0,0 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

Binary file not shown.

View file

@ -1 +0,0 @@
13741

View file

@ -10,6 +10,7 @@ SQLALCHEMY_DATABASE_URI="postgres://wot:wot@192.168.1.47/wot"
OPENID_FS_STORE_PATH="tmp" OPENID_FS_STORE_PATH="tmp"
WG_REDIRECT_URL="http://wot.anzhiganov.com/token" WG_REDIRECT_URL="http://wot.anzhiganov.com/token"
#WG_REDIRECT_URL="http://localhost:5000/token"
WG_APPLICATION_ID="502910c1c785c3c7ca2e83c9e89bde02" WG_APPLICATION_ID="502910c1c785c3c7ca2e83c9e89bde02"
# WG_OPENID_URL=https://eu.wargaming.net/id/openid/ # WG_OPENID_URL=https://eu.wargaming.net/id/openid/
WG_OPENID_URL="https://wargaming.net/id/openid/" WG_OPENID_URL="https://wargaming.net/id/openid/"
@ -25,3 +26,11 @@ CELERY_RESULT_BACKEND = 'redis://192.168.1.47:6379/4'
# 'schedule': crontab(minute="*") # 'schedule': crontab(minute="*")
# }, # },
#} #}
ROBOKASSA = {
'ENABLED': True,
'MODE': '',
'LOGIN': '',
'PASSWORD1': '',
'PASSWORD2': '',
}

View file

@ -0,0 +1,26 @@
"""empty message
Revision ID: 43d399aefb51
Revises: 92040f86c12b
Create Date: 2017-10-22 04:03:08.207413
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import JSONB
# revision identifiers, used by Alembic.
revision = '43d399aefb51'
down_revision = '92040f86c12b'
branch_labels = None
depends_on = None
def upgrade():
op.add_column('rush_accounts', sa.Column('finish_data', JSONB, nullable=True))
op.add_column('rush_accounts', sa.Column('start_data', JSONB, nullable=True))
def downgrade():
op.drop_column('rush_accounts', 'start_data')
op.drop_column('rush_accounts', 'finish_data')

View file

@ -0,0 +1,43 @@
"""empty message
Revision ID: 92040f86c12b
Revises: e75eb58a894e
Create Date: 2017-10-20 03:55:16.731533
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = '92040f86c12b'
down_revision = 'e75eb58a894e'
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
'rush',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('at_start', sa.DateTime(), nullable=False),
sa.Column('at_finish', sa.DateTime(), nullable=False),
sa.Column('bet', sa.Integer(), nullable=False),
sa.Column('status', sa.String(length=32), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table(
'rush_accounts',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('rush_id', sa.Integer(), nullable=False),
sa.Column('account_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['account_id'], ['wot_accounts.account_id'], ),
sa.ForeignKeyConstraint(['rush_id'], ['rush.id'], ),
sa.PrimaryKeyConstraint('id')
)
def downgrade():
op.drop_table('rush_accounts')
op.drop_table('rush')

View file

@ -0,0 +1,42 @@
"""empty message
Revision ID: a0c2b2ad3a28
Revises: 43d399aefb51
Create Date: 2017-10-23 02:39:35.899706
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = 'a0c2b2ad3a28'
down_revision = '43d399aefb51'
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
'user_wallet',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user', sa.Integer(), nullable=False),
sa.Column('balance', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['user'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table(
'user_wallet_transactions',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('status', sa.String(length=32), nullable=False),
sa.Column('amount', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['user'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
def downgrade():
op.drop_table('user_wallet_transactions')
op.drop_table('user_wallet')

View file

@ -1,8 +1,13 @@
flask flask
flask_sqlalchemy flask_sqlalchemy
Flask-Migrate Flask-Migrate
Flask-Script
validators validators
jsonschema jsonschema
Flask-JWT Flask-JWT
Flask-OpenID Flask-OpenID
requests requests
celery
psycopg2
redis
validator

3
run_celery_beat.sh Normal file
View file

@ -0,0 +1,3 @@
#!/usr/bin/env python
celery beat -A run_celery.celery -l debug

3
run_celery_worker.sh Normal file
View file

@ -0,0 +1,3 @@
#!/usr/bin/env python
celery worker -A run_celery.celery -l debug

View file

@ -4,9 +4,7 @@ from flask import Flask, render_template, g, session
from wotstats.database import db, migrate from wotstats.database import db, migrate
from wotstats.openid import oid from wotstats.openid import oid
from wotstats.pending_tasks import celery from wotstats.pending_tasks import celery
from wotstats.views.home import pages_home from wotstats.views import *
from wotstats.views.account import pages_account
from wotstats.views.wallet import pages_wallet
def init_app(): def init_app():
@ -23,7 +21,10 @@ def init_app():
app.register_blueprint(pages_home) app.register_blueprint(pages_home)
app.register_blueprint(pages_account) app.register_blueprint(pages_account)
app.register_blueprint(pages_technic)
app.register_blueprint(pages_achievements)
app.register_blueprint(pages_wallet) app.register_blueprint(pages_wallet)
app.register_blueprint(pages_rush)
@app.before_request @app.before_request
def lookup_current_user(): def lookup_current_user():

View file

@ -1,4 +1,6 @@
import re import re
import requests
from .texts import statistics
def parse_wargaming_openid_url(url): def parse_wargaming_openid_url(url):
@ -9,3 +11,15 @@ def parse_wargaming_openid_url(url):
""" """
pattern = '^https?.*id\/([0-9]+)-(\w+)\/$' pattern = '^https?.*id\/([0-9]+)-(\w+)\/$'
return re.findall(pattern, url)[0] return re.findall(pattern, url)[0]
def get_player_personal_data(application_id, user_id):
url = "https://api.worldoftanks.ru/wot/account/info/"
payload = {
# "application_id": current_app.config['WG_APPLICATION_ID'],
"application_id": application_id,
"account_id": user_id
}
__ = requests.get(url, params=payload).json()
return __.get('data', {}).get(user_id)

637
wotstats/lib/texts.py Normal file
View file

@ -0,0 +1,637 @@
# coding: utf-8
statistics = {
"frags": u"Количество и модели уничтоженной игроком техники. Приватные данные игрока.",
"trees_cut": u"Количество поваленных деревьев",
# Общая статистика для Случайных и клановых боев без учёта Глобальной карты 2.0.
"all": {
"avg_damage_assisted": u"Средний урон, нанесённый с вашей помощью. Значение считается с версии игры 8.8.",
"avg_damage_assisted_radio": u"Средний урон по вашим разведданным. Значение считается с версии игры 8.8.",
"avg_damage_assisted_track": u"Средний урон после вашего попадания, сбившего гусеницу. Значение считается с версии игры 8.8.",
"avg_damage_blocked": u"Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.",
"battle_avg_xp": u"Средний опыт за бой",
"battles": u"Проведено боёв",
"battles_on_stunning_vehicles": u"Количество боёв на технике, причиняющей оглушение",
"capture_points": u"Очки захвата базы",
"damage_dealt": u"Нанесено повреждений",
"damage_received": u"Получено урона",
"direct_hits_received": u"Количество полученных прямых попаданий",
"draws": u"Ничьи",
"dropped_capture_points": u"Очки защиты базы",
"explosion_hits": u"Количество нанесённых осколочно-фугасных попаданий",
"explosion_hits_received": u"Количество полученных осколочно-фугасных попаданий",
"frags": u"Уничтожено техники",
"hits": u"Попадания",
"hits_percents": u"Процент попаданий",
"losses": u"Поражения",
"max_damage": u"Максимальный урон за бой",
"max_damage_tank_id": u"Техника, на которой был нанесён максимальный урон за бой",
"max_frags": u"Максимум уничтожено за бой",
"max_frags_tank_id": u"Техника, на которой уничтожено максимальное количество противников за бой",
"max_xp": u"Максимальный опыт за бой",
"max_xp_tank_id": u"Техника, на которой получен максимальный опыт за бой",
"no_damage_direct_hits_received": u"Количество полученных прямых попаданий, не нанёсших урон",
"piercings": u"Количество пробитий",
"piercings_received": u"Количество полученных пробитий",
"shots": u"Произведено выстрелов",
"spotted": u"Обнаружено противников",
"stun_assisted_damage": u"Урон по оглушённым вами целям",
"stun_number": u"Количество оглушений, причинённых экипажу противника",
"survived_battles": u"Выжил в боях",
"tanking_factor": u"Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.",
"wins": u"Победы",
"xp": u"Суммарный опыт",
},
# Статистика боёв в составе клана
"clan": {
"avg_damage_assisted": u"Средний урон, нанесённый с вашей помощью. Значение считается с версии игры 8.9.",
"avg_damage_assisted_radio": u"Средний урон по вашим разведданным. Значение считается с версии игры 8.9.",
"avg_damage_assisted_track": u"Средний урон после вашего попадания, сбившего гусеницу. Значение считается с версии игры 8.9.",
"avg_damage_blocked": u"Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.",
"battle_avg_xp": u"Средний опыт за бой",
"battles": u"Проведено боёв",
"battles_on_stunning_vehicles": u"Количество боёв на технике, причиняющей оглушение",
"capture_points": u"Очки захвата базы",
"damage_dealt": u"Нанесено повреждений",
"damage_received": u"Получено урона",
"direct_hits_received": u"Количество полученных прямых попаданий",
"draws": u"Ничьи",
"dropped_capture_points": u"Очки защиты базы",
"explosion_hits": u"Количество нанесённых осколочно-фугасных попаданий",
"explosion_hits_received": u"Количество полученных осколочно-фугасных попаданий",
"frags": u"Уничтожено техники",
"hits": u"Попадания",
"hits_percents": u"Процент попаданий",
"losses": u"Поражения",
"no_damage_direct_hits_received": u"Количество полученных прямых попаданий, не нанёсших урон",
"piercings": u"Количество пробитий",
"piercings_received": u"Количество полученных пробитий",
"shots": u"Произведено выстрелов",
"spotted": u"Обнаружено противников",
"stun_assisted_damage": u"Урон по оглушённым вами целям",
"stun_number": u"Количество оглушений, причинённых экипажу противника",
"survived_battles": u"Выжил в боях",
"tanking_factor": u"Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.",
"wins": u"Победы",
"xp": u"Суммарный опыт",
},
# Статистика боёв в составе роты
"company": {
"avg_damage_assisted": u"Средний урон, нанесённый с вашей помощью. Значение считается с версии игры 8.9.",
"avg_damage_assisted_radio": u"Средний урон по вашим разведданным. Значение считается с версии игры 8.9.",
"avg_damage_assisted_track": u"Средний урон после вашего попадания, сбившего гусеницу. Значение считается с версии игры 8.9.",
"avg_damage_blocked": u"Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.",
"battle_avg_xp": u"Средний опыт за бой",
"battles": u"Проведено боёв",
"battles_on_stunning_vehicles": u"Количество боёв на технике, причиняющей оглушение",
"capture_points": u"Очки захвата базы",
"damage_dealt": u"Нанесено повреждений",
"damage_received": u"Получено урона",
"direct_hits_received": u"Количество полученных прямых попаданий",
"draws": u"Ничьи",
"dropped_capture_points": u"Очки защиты базы",
"explosion_hits": u"Количество нанесённых осколочно-фугасных попаданий",
"explosion_hits_received": u"Количество полученных осколочно-фугасных попаданий",
"frags": u"Уничтожено техники",
"hits": u"Попадания",
"hits_percents": u"Процент попаданий",
"losses": u"Поражения",
"no_damage_direct_hits_received": u"Количество полученных прямых попаданий, не нанёсших урон",
"piercings": u"Количество пробитий",
"piercings_received": u"Количество полученных пробитий",
"shots": u"Произведено выстрелов",
"spotted": u"Обнаружено противников",
"stun_assisted_damage": u"Урон по оглушённым вами целям",
"stun_number": u"Количество оглушений, причинённых экипажу противника",
"survived_battles": u"Выжил в боях",
"tanking_factor": u"Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.",
"wins": u"Победы",
"xp": u"Суммарный опыт"
},
# Статистика в типе боя "Генеральное сражение".
"epic": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'max_damage': u'Максимальный урон за бой',
'max_damage_tank_id': u'Техника, на которой был нанесён максимальный урон за бой',
'max_frags': u'Максимум уничтожено за бой',
'max_frags_tank_id': u'Техника, на которой уничтожено максимальное количество противников за бой',
'max_xp': u'Максимальный опыт за бой',
'max_xp_tank_id': u'Техника, на которой получен максимальный опыт за бой',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт'
},
# Статистика в режиме «Бой до последнего».
"fallout": {
'avatar_damage_dealt': u'Урон, нанесённый при помощи боевых резервов',
'avatar_frags': u'Уничтожено при помощи боевых резервов',
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'death_count': u'Погиб',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'flag_capture': u'Захвачено флагов в составе взвода',
'flag_capture_solo': u'Захвачено флагов в роли одиночного игрока',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'max_damage': u'Максимальный урон за бой',
'max_damage_tank_id': u'Техника, на которой был нанесён максимальный урон за бой',
'max_damage_with_avatar': u'Максимальный урон, нанесённый в одном бою, включая урон от аватара',
'max_frags': u'Максимум уничтожено за бой',
'max_frags_tank_id': u'Техника, на которой уничтожено максимальное количество противников за бой',
'max_frags_with_avatar': u'Максимальное количество уничтоженной техники, включая технику, уничтоженную аватаром',
'max_win_points': u'Максимальное количество Очков победы, заработанное в режиме «Бой до последнего»',
'max_xp': u'Максимальный опыт за бой',
'max_xp_tank_id': u'Техника, на которой получен максимальный опыт за бой',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'resource_absorbed': u'Ресурсы, захваченные на ресурсных точках',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'win_points': u'Очки победы',
'wins': u'Победы',
'xp': u'Суммарный опыт'
},
# Статистика боёв на Глобальной карте в Абсолютном дивизионе.
"globalmap_absolute": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт',
},
# Статистика боёв на Глобальной карте в Чемпионском дивизионе.
"globalmap_champion": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт'
},
# Статистика боёв на Глобальной карте в Среднем дивизионе.
"globalmap_middle": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт',
},
# Статистика исторических боёв
"historical": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'max_damage': u'Максимальный урон за бой',
'max_damage_tank_id': u'Техника, на которой был нанесён максимальный урон за бой',
'max_frags': u'Максимум уничтожено за бой',
'max_frags_tank_id': u'Техника, на которой уничтожено максимальное количество противников за бой',
'max_xp': u'Максимальный опыт за бой',
'max_xp_tank_id': u'Техника, на которой получен максимальный опыт за бой',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт',
},
# Статистика случайных боёв.
"random": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт',
},
# Статистика по Ранговым боям.
"ranked_battles": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'max_damage': u'Максимальный урон за бой',
'max_damage_tank_id': u'Техника, на которой был нанесён максимальный урон за бой',
'max_frags': u'Максимум уничтожено за бой',
'max_frags_tank_id': u'Техника, на которой уничтожено максимальное количество противников за бой',
'max_xp': u'Максимальный опыт за бой',
'max_xp_tank_id': u'Техника, на которой получен максимальный опыт за бой',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт',
},
# Текущая статистика по Ранговым боям.
"ranked_battles_current": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'max_damage': u'Максимальный урон за бой',
'max_damage_tank_id': u'Техника, на которой был нанесён максимальный урон за бой',
'max_frags': u'Максимум уничтожено за бой',
'max_frags_tank_id': u'Техника, на которой уничтожено максимальное количество противников за бой',
'max_xp': u'Максимальный опыт за бой',
'max_xp_tank_id': u'Техника, на которой получен максимальный опыт за бой',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт'
},
# Предыдущая статистика по Ранговым боям.
"ranked_battles_previous": {
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'max_damage': u'Максимальный урон за бой',
'max_damage_tank_id': u'Техника, на которой был нанесён максимальный урон за бой',
'max_frags': u'Максимум уничтожено за бой',
'max_frags_tank_id': u'Техника, на которой уничтожено максимальное количество противников за бой',
'max_xp': u'Максимальный опыт за бой',
'max_xp_tank_id': u'Техника, на которой получен максимальный опыт за бой',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': "Количество полученных пробитий",
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт'
},
# Статистика командных боёв постоянных команд
"regular_team": {
# Внимание! Поле будет отключено.
'avg_damage_assisted': u'Средний урон, нанесённый с вашей помощью',
'avg_damage_assisted_radio': u'Средний урон по вашим разведданным',
'avg_damage_assisted_track': u'Средний урон после вашего попадания, сбившего гусеницу',
'avg_damage_blocked': u'Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.',
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'max_damage': u'Максимальный урон за бой',
'max_damage_tank_id': u'Техника, на которой был нанесён максимальный урон за бой',
'max_frags': u'Максимум уничтожено за бой',
'max_frags_tank_id': u'Техника, на которой уничтожено максимальное количество противников за бой',
'max_xp': u'Максимальный опыт за бой',
'max_xp_tank_id': u'Техника, на которой получен максимальный опыт за бой',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
'survived_battles': u'Выжил в боях',
'tanking_factor': u'Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.',
'wins': u'Победы',
'xp': u'Суммарный опыт'
},
# Общая по всем кланам статистика боёв игрока в режиме обороны Укрепрайона
"stronghold_defense": {
'battle_avg_xp': u'Средний опыт за бой',
'battles': u'Проведено боёв',
'battles_on_stunning_vehicles': u'Количество боёв на технике, причиняющей оглушение',
'capture_points': u'Очки захвата базы',
'damage_dealt': u'Нанесено повреждений',
'damage_received': u'Получено урона',
'direct_hits_received': u'Количество полученных прямых попаданий',
'draws': u'Ничьи',
'dropped_capture_points': u'Очки защиты базы',
'explosion_hits': u'Количество нанесённых осколочно-фугасных попаданий',
'explosion_hits_received': u'Количество полученных осколочно-фугасных попаданий',
'frags': u'Уничтожено техники',
'hits': u'Попадания',
'hits_percents': u'Процент попаданий',
'losses': u'Поражения',
'max_damage': u'Максимальный урон за бой',
'max_damage_tank_id': u'Техника, на которой был нанесён максимальный урон за бой',
'max_frags': u'Максимум уничтожено за бой',
'max_frags_tank_id': u'Техника, на которой уничтожено максимальное количество противников за бой',
'max_xp': u'Максимальный опыт за бой',
'max_xp_tank_id': u'Техника, на которой получен максимальный опыт за бой',
'no_damage_direct_hits_received': u'Количество полученных прямых попаданий, не нанёсших урон',
'piercings': u'Количество пробитий',
'piercings_received': u'Количество полученных пробитий',
'shots': u'Произведено выстрелов',
'spotted': u'Обнаружено противников',
'stun_assisted_damage': u'Урон по оглушённым вами целям',
'stun_number': u'Количество оглушений, причинённых экипажу противника',
"survived_battles": u"Выжил в боях",
"tanking_factor": u"Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.",
"wins": u"Победы",
"xp": u"Суммарный опыт",
},
# Общая по всем кланам статистика боёв игрока в режиме вылазок Укрепрайона
"stronghold_skirmish": {
"battle_avg_xp": u"Средний опыт за бой",
"battles": u"Проведено боёв",
"battles_on_stunning_vehicles": u"Количество боёв на технике, причиняющей оглушение",
"capture_points": u"Очки захвата базы",
"damage_dealt": u"Нанесено повреждений",
"damage_received": u"Получено урона",
"direct_hits_received": u"Количество полученных прямых попаданий",
"draws": u"Ничьи",
"dropped_capture_points": u"Очки защиты базы",
"explosion_hits": u"Количество нанесённых осколочно-фугасных попаданий",
"explosion_hits_received": u"Количество полученных осколочно-фугасных попаданий",
"frags": u"Уничтожено техники",
"hits": u"Попадания",
"hits_percents": u"Процент попаданий",
"losses": u"Поражения",
"max_damage": u"Максимальный урон за бой",
"max_damage_tank_id": u"Техника, на которой был нанесён максимальный урон за бой",
"max_frags": u"Максимум уничтожено за бой",
"max_frags_tank_id": u"Техника, на которой уничтожено максимальное количество противников за бой",
"max_xp": u"Максимальный опыт за бой",
"max_xp_tank_id": u"Техника, на которой получен максимальный опыт за бой",
"no_damage_direct_hits_received": u"Количество полученных прямых попаданий, не нанёсших урон",
"piercings": u"Количество пробитий",
"piercings_received": u"Количество полученных пробитий",
"shots": u"Произведено выстрелов",
"spotted": u"Обнаружено противников",
"stun_assisted_damage": u"Урон по оглушённым вами целям",
"stun_number": u"Количество оглушений, причинённых экипажу противника",
"survived_battles": u"Выжил в боях",
"tanking_factor": u"Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.",
"wins": u"Победы",
"xp": u"Суммарный опыт",
},
# Статистика командных боёв
"team": {
"avg_damage_assisted": u"Средний урон, нанесённый с вашей помощью",
"avg_damage_assisted_radio": u"Средний урон по вашим разведданным",
"avg_damage_assisted_track": u"Средний урон после вашего попадания, сбившего гусеницу",
"avg_damage_blocked": u"Средний заблокированный бронёй урон за бой. Заблокированный бронёй урон — это урон от снарядов (бронебойных, кумулятивных и подкалиберных), которые попали в танк, но не нанесли урона. Значение считается с версии игры 9.0.",
"battle_avg_xp": u"Средний опыт за бой",
"battles": u"Проведено боёв",
"battles_on_stunning_vehicles": u"Количество боёв на технике, причиняющей оглушение",
"capture_points": u"Очки захвата базы",
"damage_dealt": u"Нанесено повреждений",
"damage_received": u"Получено урона",
"direct_hits_received": u"Количество полученных прямых попаданий",
"draws": u"Ничьи",
"dropped_capture_points": u"Очки защиты базы",
"explosion_hits": u"Количество нанесённых осколочно-фугасных попаданий",
"explosion_hits_received": u"Количество полученных осколочно-фугасных попаданий",
"frags": u"Уничтожено техники",
"hits": u"Попадания",
"hits_percents": u"Процент попаданий",
"losses": u"Поражения",
"max_damage": u"Максимальный урон за бой",
"max_damage_tank_id": u"Техника, на которой был нанесён максимальный урон за бой",
"max_frags": u"Максимум уничтожено за бой",
"max_frags_tank_id": u"Техника, на которой уничтожено максимальное количество противников за бой",
"max_xp": u"Максимальный опыт за бой",
"max_xp_tank_id": u"Техника, на которой получен максимальный опыт за бой",
"no_damage_direct_hits_received": u"Количество полученных прямых попаданий, не нанёсших урон",
"piercings": u"Количество пробитий",
"piercings_received": u"Количество полученных пробитий",
"shots": u"Произведено выстрелов",
"spotted": u"Обнаружено противников",
"stun_assisted_damage": u"Урон по оглушённым вами целям",
"stun_number": u"Количество оглушений, причинённых экипажу противника",
"survived_battle": u"Выжил в боях",
"tanking_factor": u"Отношение заблокированного бронёй урона к полученному игроком урону от бронебойных, кумулятивных, подкалиберных снарядов. Значение считается с версии игры 9.0.",
"wins": u"Победы",
"xp": u"Суммарный опыт",
}
}

View file

@ -1,5 +1,6 @@
from .user import User from .user import User
from .userwallet import UserWallet, UserWalletTransactions
from .userwottokens import UserWotTokens from .userwottokens import UserWotTokens
from .userwotdetails import UserWotDetails from .userwotdetails import UserWotDetails
# from .userwotstats import UserWotStats # from .userwotstats import UserWotStats
@ -7,3 +8,5 @@ from .userwotdata import UserWotData
from .wotaccounts import WotAccounts from .wotaccounts import WotAccounts
from .wotaccountsstats import WotAccountsStats from .wotaccountsstats import WotAccountsStats
from .rush import Rush
from .rushaccounts import RushAccounts

20
wotstats/models/rush.py Normal file
View file

@ -0,0 +1,20 @@
# from sqlalchemy.dialects.postgresql import ARRAY, HSTORE
from wotstats.database import db
class Rush(db.Model):
id = db.Column(db.Integer, primary_key=True)
at_start = db.Column(db.DateTime, nullable=False)
at_finish = db.Column(db.DateTime, nullable=False)
bet = db.Column(db.Integer, nullable=False, default=0)
# preparation, started, finished, canceled
status = db.Column(db.String(32), nullable=False, default='preparation')
def __init__(self):
pass
def __repr__(self):
return '<Rush id={} at_start={} at_finish={} bet={} status={}>'.format(
self.id, self.at_start, self.at_finish, self.bet, self.status
)

View file

@ -0,0 +1,23 @@
from sqlalchemy.dialects.postgresql import JSONB
from wotstats.database import db
class RushAccounts(db.Model):
id = db.Column(db.Integer, primary_key=True)
rush_id = db.Column(db.Integer, db.ForeignKey('rush.id'), nullable=False)
account_id = db.Column(db.Integer, db.ForeignKey('wot_accounts.account_id'), nullable=False)
# {"battles": 0, "draws": 0, "wins": 0, "loses": 0}
start_data = db.Column(JSONB, nullable=True, default={})
# {"battles": 0, "draws": 0, "wins": 0, "loses": 0}
finish_data = db.Column(JSONB, nullable=True, default={})
def __init__(self, account_id, rush_id):
self.account_id = account_id
self.rush_id = rush_id
def __repr__(self):
return '<RushAccounts rush_id={} account_id={}>'.format(
self.rush_id, self.account_id
)

View file

@ -0,0 +1,34 @@
from sqlalchemy.dialects.postgresql import ARRAY, HSTORE
from wotstats.database import db
class UserWallet(db.Model):
id = db.Column(db.Integer, primary_key=True)
user = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
balance = db.Column(db.Integer, default=0)
def __init__(self, user, balance=0):
self.user = user
self.balance = balance
def __repr__(self):
return '<UserWallet id={} user={} balance={}>'.format(
self.id, self.user, self.balance
)
class UserWalletTransactions(db.Model):
id = db.Column(db.Integer, primary_key=True)
user = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
created_at = db.Column(db.DateTime, nullable=False)
status = db.Column(db.String(32), nullable=False)
amount = db.Column(db.Integer)
def __init__(self, user):
self.user = user
def __repr__(self):
return '<Transactions id={} user={} amount={} status={}>'.format(
self.id, self.user, self.amount, self.status
)

View file

@ -24,4 +24,6 @@ class UserWotTokens(db.Model):
# pass # pass
def __repr__(self): def __repr__(self):
return '<User id={} user={} access_token={} expires_at={}>'.format(self.id, self.user, self.access_token, self.expires_at) return '<User id={} user={} access_token={} expires_at={}>'.format(
self.id, self.user, self.access_token, self.expires_at
)

2337
wotstats/static/css/font-awesome.css vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,16 +1,154 @@
import time import time
from datetime import timedelta import requests
import json
from datetime import timedelta, datetime
from flask import current_app from flask import current_app
from wotstats.pending_tasks import celery from wotstats.pending_tasks import celery
from wotstats.database import db
from wotstats.models import UserWotTokens
from wotstats.models import Rush, RushAccounts
@celery.task(name='wotstats.tasks.hello') @celery.task(name='wotstats.tasks.tokens_prolongate')
def hello(): def tokens_prolongate():
time.sleep(3) time.sleep(3)
# TODO: get oldest token
# UserWotTokens.select()
# TODO: try to prolongate token
# TODO: if prolongate response fails then delete token from database
# TODO: if all ok then update token from database
print 111
@celery.task(name='wotstats.tasks.get_stats_tokenized_users')
def get_stats_tokenized_users():
time.sleep(3)
print 111
@celery.task(name='wotstats.tasks.crontab_rush_preparation')
def crontab_rush_preparation():
""""""
if Rush.query.filter_by(status='preparation').count() == 0:
now = datetime.now().replace(minute=0, second=0)
new_rush = Rush()
new_rush.at_start = now + timedelta(hours=1)
new_rush.at_finish = now + timedelta(hours=24)
try:
db.session.add(new_rush)
db.session.commit()
except Exception as e:
print e
db.session.rollback()
else:
return True
return False
@celery.task(name='wotstats.tasks.crontab_rush_start')
def crontab_rush_start():
to_start = Rush.query.filter(
Rush.status == 'preparation', Rush.at_start <= datetime.now())
if to_start.count() > 0:
p = to_start.first()
# Count
rush_accounts = RushAccounts.query.filter(
RushAccounts.rush_id == p.id
)
if rush_accounts.count() == 0:
p.status = 'canceled'
db.session.commit()
return True
else:
for ra in rush_accounts.all():
# Get current stats by ra.account_id
# Save battle stats to database
#
app_id = current_app.config['WG_APPLICATION_ID']
url = 'https://api.worldoftanks.ru/wot/account/info/'
__ = requests.get('{}?application_id={}&account_id={}'.format(url, app_id, ra.account_id)).json()
account_statistics = __.get('data', {}).get("{}".format(ra.account_id)).get('statistics', {})
account_data = __['data']["{}".format(ra.account_id)]['statistics']['all']
data = {
'battles': account_data['battles'],
'wins': account_data['wins'],
'losses': account_data['losses'],
'draws': account_data['draws'],
}
xx = RushAccounts.query.filter(
RushAccounts.rush_id == p.id,
RushAccounts.account_id == ra.account_id
).first()
xx.start_data = data
db.session.commit()
pass
p.status = 'started'
db.session.commit()
return True
else:
return False
@celery.task(name='wotstats.tasks.crontab_rush_finish')
def crontab_rush_finish():
to_finish = Rush.query.filter(
Rush.status == 'started', Rush.at_finish <= datetime.now())
if to_finish.count() == 0:
return False
finish_stats = dict()
p = to_finish.first()
# Harvert stats for all rush members
for ra in RushAccounts.query.filter(RushAccounts.rush_id == p.id):
# TODO: Get WOT accoount data
# TODO: Get Stats from WOT server
# TODO: Save Stats
account_id = ra.account_id
# Get current stats by ra.account_id
# Save battle stats to database
#
app_id = current_app.config['WG_APPLICATION_ID']
url = 'https://api.worldoftanks.ru/wot/account/info/'
__ = requests.get('{}?application_id={}&account_id={}'.format(url, app_id, account_id)).json()
account_statistics = __.get('data', {}).get("{}".format(ra.account_id)).get('statistics', {})
account_data = __['data']["{}".format(account_id)]['statistics']['all']
data = {
'battles': account_data['battles'],
'wins': account_data['wins'],
'losses': account_data['losses'],
'draws': account_data['draws'],
}
xx = RushAccounts.query.filter(
RushAccounts.rush_id == p.id,
RushAccounts.account_id == account_id
).first()
xx.finish_data = data
db.session.commit()
finish_stats[account_id] = {
'wins': xx.finish_data['wins'] - account_data['wins'],
'battles': xx.finish_data['battles'] - account_data['battles']
}
result = sorted(finish_stats.items(), key=lambda t: t[1]['wins'], reverse=True)
pass
# TODO: ...
p.status = 'finished'
db.session.commit()
# time.sleep(3)
# current_app.log.error('wdwqd') # current_app.log.error('wdwqd')
# with current_app.test_request_context() as request: # with current_app.test_request_context() as request:
# print('Hello {0!r}'.format(request)) # print('Hello {0!r}'.format(request))
print 111 # print 111
@celery.task @celery.task
@ -26,7 +164,9 @@ def mail_welcome():
@celery.on_after_configure.connect @celery.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs): def setup_periodic_tasks(sender, **kwargs):
# Calls test('hello') every 10 seconds. # Calls test('hello') every 10 seconds.
sender.add_periodic_task(10.0, hello.s(), name='add every 10') sender.add_periodic_task(10.0, crontab_rush_preparation.s(), name='prepare every 10')
sender.add_periodic_task(10.0, crontab_rush_start.s(), name='start every 10')
sender.add_periodic_task(10.0, crontab_rush_finish.s(), name='finish every 10')
# Calls test('world') every 30 seconds # Calls test('world') every 30 seconds
# sender.add_periodic_task(30.0, test.s('world'), expires=10) # sender.add_periodic_task(30.0, test.s('world'), expires=10)

View file

@ -7,11 +7,20 @@
<!-- load MUI --> <!-- load MUI -->
<link href="//cdn.muicss.com/mui-0.9.22/css/mui.min.css" rel="stylesheet" type="text/css" /> <link href="//cdn.muicss.com/mui-0.9.22/css/mui.min.css" rel="stylesheet" type="text/css" />
<script src="//cdn.muicss.com/mui-0.9.22/js/mui.min.js"></script> <script src="//cdn.muicss.com/mui-0.9.22/js/mui.min.js"></script>
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
<style>
body {
background-color: #f0f0f0;
}
</style>
</head> </head>
<body> <body>
<div style="text-align: center">
<img src="{{ url_for('static', filename='images/logo.png') }}" >
</div>
<div class="mui-container"> <div class="mui-container">
<div class="mui-panel"> <div class="mui-panel">
<h1>wotstats</h1> <!-- <h1>wotstats</h1> -->
{% if session['openid'] %} {% if session['openid'] %}
<div> <div>
{% if 'openid' in session %} {% if 'openid' in session %}
@ -19,18 +28,22 @@
{% else %} {% else %}
<!-- {{ session['email'] }} --> <!-- {{ session['email'] }} -->
{% endif %} {% endif %}
<a href="{{ url_for('pages_account.index') }}" class="mui-btn mui-btn--raised">my statistics</a> <a href="{{ url_for('pages_account.index') }}" class="mui-btn mui-btn--raised">Моя статистика</a>
<a href="{{ url_for('pages_wallet.index') }}" class="mui-btn mui-btn--raised">wallet</a> <a href="{{ url_for('technic.index') }}" class="mui-btn mui-btn--raised">Моя техника</a>
<a href="{{ url_for('pages_home.logout') }}" class="mui-btn mui-btn--primary mui-btn--raised">logout</a> <a href="{{ url_for('achievements.index') }}" class="mui-btn mui-btn--raised">Мои достижения</a>
<a href="{{ url_for('pages_wallet.index') }}" class="mui-btn mui-btn--raised">Кошелёк</a>
<a href="{{ url_for('pages_rush.index') }}" class="mui-btn mui-btn--raised">Турниры</a>
<a href="{{ url_for('pages_home.logout') }}" class="mui-btn mui-btn--primary mui-btn--raised">Выход</a>
</div> </div>
{% else %} {% else %}
<div> <div>
<a href="{{ url_for('pages_home.login') }}" class="mui-btn mui-btn--primary mui-btn--raised">Sign In</a> <a href="{{ url_for('pages_home.login') }}" class="mui-btn mui-btn--primary mui-btn--raised">Войти</a>
</div> </div>
{% endif %} {% endif %}
{% block content %}{% endblock %} {% block content %}{% endblock %}
<!-- <button class="mui-btn mui-btn--primary mui-btn--raised">My Button</button> --> <!-- <button class="mui-btn mui-btn--primary mui-btn--raised">My Button</button> -->
</div> </div>
</div> </div>
{% block js %}{% endblock %}
</body> </body>
</html> </html>

View file

@ -0,0 +1,40 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h2>Достижения</h2>
<ul class="mui-tabs__bar">
<li class="mui--is-active"><a data-mui-toggle="tab" data-mui-controls="pane-default-1">Полученные достижения</a></li>
<li><a data-mui-toggle="tab" data-mui-controls="pane-default-2">Прогресс достижений</a></li>
<li><a data-mui-toggle="tab" data-mui-controls="pane-default-3">Максимальные значения серийных достижений</a></li>
</ul>
<div class="mui-tabs__pane mui--is-active" id="pane-default-1">
<table class="mui-table mui-table--bordered">
{% for achievement in account_achievements['achievements'] %}
<tr>
<td>{{ achievement }}</td>
<td>{{ account_achievements['achievements'][achievement] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-2">
<table class="mui-table mui-table--bordered">
{% for achievement in account_achievements['flags'] %}
<tr>
<td>{{ achievement }}</td>
<td>{{ account_achievements['flags'][achievement] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-3">
<table class="mui-table mui-table--bordered">
{% for achievement in account_achievements['max_series'] %}
<tr>
<td>{{ achievement }}</td>
<td>{{ account_achievements['max_series'][achievement] }}</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}

View file

@ -1,22 +1,123 @@
{% extends 'layouts/main.html' %} {% extends 'layouts/main.html' %}
{% block content %} {% block content %}
<h2>My Statistics</h2> <h2>Моя статистика</h2>
{% for x in account_statistics.statistics %}
<h3>{{ x }}</h3> <div class="mui-row">
{% if account_statistics.statistics[x] is mapping %} <div class="mui-col-md-3">
<table class="mui-table mui-table--bordered"> <ul class="mui-tabs">
{% for c in account_statistics.statistics[x] %} <li class="mui--is-active"><a data-mui-toggle="tab" data-mui-controls="pane-default-1">Суммарная статистика</a></li>
<tr> <li><a data-mui-toggle="tab" data-mui-controls="pane-default-2">Бои в составе клана</a></li>
<td>{{ c }}</td><td>{{ account_statistics.statistics[x][c] }}</td> <li><a data-mui-toggle="tab" data-mui-controls="pane-default-3">Бои в составе роты</a></li>
</tr> <li><a data-mui-toggle="tab" data-mui-controls="pane-default-4">Командные бои</a></li>
{% endfor %} <li><a data-mui-toggle="tab" data-mui-controls="pane-default-5">Оборона Укрепрайона</a></li>
<li><a data-mui-toggle="tab" data-mui-controls="pane-default-6">Вылазки Укрепрайона</a></li>
<li><a data-mui-toggle="tab" data-mui-controls="pane-default-7">Разное</a></li>
</ul> </ul>
{% else %} </div>
<ul> <div class="mui-col-md-9">
<li>{{ x }}: {{ account_statistics.statistics[x] }}</li> <div class="mui-tabs__pane mui--is-active" id="pane-default-1">
</ul> <h2>Суммарная статистика</h2>
{% endif %} <table class="mui-table mui-table--bordered">
</table> {% for c in account_statistics.statistics['all'] %}
{% endfor %} <tr>
<td>{{ texts_statistics['all'][c] }}</td>
<td>{{ account_statistics.statistics['all'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-2">
<h2>Бои в составе клана</h2>
<table class="mui-table mui-table--bordered">
{% for c in account_statistics.statistics['clan'] %}
<tr>
<td>{{ texts_statistics['clan'][c] }}</td>
<td>{{ account_statistics.statistics['clan'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-3">
<h2>Бои в составе роты</h2>
<table class="mui-table mui-table--bordered">
{% for c in account_statistics.statistics['company'] %}
<tr>
<td>{{ texts_statistics['company'][c] }}</td>
<td>{{ account_statistics.statistics['company'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-4">
<h2>Командные бои</h2>
<table class="mui-table mui-table--bordered">
{% for c in account_statistics.statistics['historical'] %}
<tr>
<td>{{ texts_statistics['historical'][c] }}</td>
<td>{{ account_statistics.statistics['historical'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-5">
<h2>Оборона Укрепрайона</h2>
<table class="mui-table mui-table--bordered">
{% for c in account_statistics.statistics['stronghold_defense'] %}
<tr>
<td>{{ texts_statistics['stronghold_defense'][c] }}</td>
<td>{{ account_statistics.statistics['stronghold_defense'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-6">
<h2>Вылазки Укрепрайона</h2>
<table class="mui-table mui-table--bordered">
{% for c in account_statistics.statistics['stronghold_skirmish'] %}
<tr>
<td>{{ texts_statistics['stronghold_skirmish'][c] }}</td>
<td>{{ account_statistics.statistics['stronghold_skirmish'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-7">
<h2>Разное</h2>
<table class="mui-table mui-table--bordered">
<p>Поваленые деревья: {{account_statistics.statistics['trees_cut']}}
{% for c in account_statistics.statistics['flags'] %}
<tr>
<td>{{ texts_statistics['flags'][c] }}</td>
<td>{{ account_statistics.statistics['flags'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
{#
<div class="mui-tabs__pane" id="pane-default-3">
{% for x in account_statistics.statistics %}
<h3>{{ x }}</h3>
{% if account_statistics.statistics[x] is mapping %}
<table class="mui-table mui-table--bordered">
{% for c in account_statistics.statistics[x] %}
<tr>
<td>{{ c }}</td>
<td>{{ account_statistics.statistics[x][c] }}</td>
</tr>
{% endfor %}
</ul>
{% else %}
<ul>
<li>{{ x }}: {{ account_statistics.statistics[x] }}</li>
</ul>
{% endif %}
</table>
{% endfor %}
</div>#}
</div>
</div>
{% endblock %} {% endblock %}

View file

@ -1,32 +0,0 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h2>My Statistics</h2>
<ul>
{% for z in account_statistics %}
<li>{{ z }}
{% if account_statistics[z] is mapping %}
<ul>
{% for x in account_statistics[z] %}
<li>{{ x }}
{% if account_statistics[z][x] is mapping %}
<ul>
{% for c in account_statistics[z][x] %}
<li>{{ c }}: {{ account_statistics[z][x][c] }}</li>
{% endfor %}
</ul>
{% else %}
<ul>
<li>{{ x }}: {{ account_statistics[z][x] }}</li>
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
{{ account_statistics[z] }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -0,0 +1,168 @@
{% extends 'layouts/main.html' %}
{% block content %}
<style>
.not_sorted {
color: #f0f0f0;
}
.sorted {
color: #000000;
};
</style>
<h2>Техника</h2>
Категории
<!-- <input type="checkbox" name="checkall" id="checkall" value="1"> Все -->
<input type="checkbox" name="level" class="level" value="1" {% if 1 in args.level %}checked{% endif %}> I
<input type="checkbox" name="level" class="level" value="2" {% if 2 in args.level %}checked{% endif %}> II
<input type="checkbox" name="level" class="level" value="3" {% if 3 in args.level %}checked{% endif %}> III
<input type="checkbox" name="level" class="level" value="4" {% if 4 in args.level %}checked{% endif %}> IV
<input type="checkbox" name="level" class="level" value="5" {% if 5 in args.level %}checked{% endif %}> V
<input type="checkbox" name="level" class="level" value="6" {% if 6 in args.level %}checked{% endif %}> VI
<input type="checkbox" name="level" class="level" value="7" {% if 7 in args.level %}checked{% endif %}> VII
<input type="checkbox" name="level" class="level" value="8" {% if 8 in args.level %}checked{% endif %}> VIII
<input type="checkbox" name="level" class="level" value="9" {% if 9 in args.level %}checked{% endif %}> IX
<input type="checkbox" name="level" class="level" value="10" {% if 10 in args.level %}checked{% endif %}> X
<table id="myTable" class="mui-table mui-table--bordered tablesorter">
<thead>
<tr>
<th>&nbsp;</th>
<th>Нация</th>
<th onclick="$(this).order_sort('level', '{% if not args.sort %}desc{% else %}asc{% endif %}')">
Уровень
{% if args.order == 'level' %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} sorted" aria-hidden="true"></i>
{% else %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} not_sorted" aria-hidden="true"></i>
{% endif %}
</th>
<th onclick="$(this).order_sort('type', '{% if not args.sort %}desc{% else %}asc{% endif %}')">
Тип
{% if args.order == 'type' %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} sorted" aria-hidden="true"></i>
{% else %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} not_sorted" aria-hidden="true"></i>
{% endif %}
</th>
<th onclick="$(this).order_sort('name', '{% if not args.sort %}desc{% else %}asc{% endif %}')">
Название
{% if args.order == 'name' %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} sorted" aria-hidden="true"></i>
{% else %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} not_sorted" aria-hidden="true"></i>
{% endif %}
</th>
<th onclick="$(this).order_sort('battles', '{% if not args.sort %}desc{% else %}asc{% endif %}')">
Кол-во боёв
{% if args.order == 'battles' %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} sorted" aria-hidden="true"></i>
{% else %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} not_sorted" aria-hidden="true"></i>
{% endif %}
</th>
<th onclick="$(this).order_sort('wins', '{% if not args.sort %}desc{% else %}asc{% endif %}')">
Кол-во побед
{% if args.order == 'wins' %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} sorted" aria-hidden="true"></i>
{% else %}
<i class="fa fa-sort-alpha-{% if args.sort %}desc{% else %}asc{% endif %} not_sorted" aria-hidden="true"></i>
{% endif %}
</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{% for x in account_technic %}
<tr>
<!-- <td>{{ x['tank_id'] }}</td> -->
<td><img src="{{ x.details.image }}" ></td>
<td>{{ x.details.nation }}</td>
<td>{{ x['details']['level'] }}</td>
<td>{{ x['details']['type'] }}</td>
<td>{{ x['details']['name'] }}</td>
<td>{{ x['statistics']['battles'] }}</td>
<td>{{ x['statistics']['wins'] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block js %}
<script src="/static/js/jquery-latest.min.js"></script>
<script src="/static/js/jquery.tablesorter.min.js"></script>
<script>
$(document).ready(function() {
var params = {
order: {% if args.order %}'{{ request.args.order }}'{% else%}'id'{% endif %},
sort: {% if args.sort %}'{{ request.args.sort }}'{% else%}'asc'{% endif %},
level: [
{% for level in args.level %}
{{ level|int }},
{% endfor %}
],
};
console.log($.param(params));
$(".level").change(function() {
console.log($(this).is(':checked'));
console.log("index: " + params.level.indexOf(parseInt($(this).val())));
if ($(this).is(':checked')) {
var int_level = parseInt($(this).val());
console.log('data: + ' + int_level);
if (params.level.indexOf(int_level) < 0) {
params.level.push(int_level);
console.log('data index: ' + params.level.indexOf(int_level));
//params.level.pop(params.level.indexOf(parseInt($(this).val())));
}
} else {
var int_level = parseInt($(this).val());
console.log($(this).is(':checked'));
console.log("index: " + params.level.indexOf(int_level));
console.log('data: - ' + int_level);
// if (!params.level.includes(parseInt($(this).val()))) {
params.level.splice(params.level.indexOf(int_level), 1);
// }
}
console.log(params.level);
//console.log(params);
//console.log($.param(params));
window.location.replace(window.location.pathname + '?' + $.param(params));
//if (params.level.includes($(this).is(':checked'))
// var action = $(this).is(':checked');
// $.post(
// "is_checked", {id: $(this).attr('id'), action: action}
// ).done(function(data, statusText, xhr) {
// switch(xhr.status) {
// case 200:
// console.log('');
// //window.location.replace(window.location.pathname + '?' + $.param(params));
// }
// })
// .fail(function(data, statusText, xhr){
// alert(xhr);
// });
});
(function($) {
$.fn.order_sort = function(order, sort) {
params.order = order;
params.sort = sort;
console.log(params);
window.location.replace(window.location.pathname + '?' + $.param(params));
}
})(jQuery);
});
</script>
{% endblock %}

View file

@ -0,0 +1,98 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h2>атистика танка</h2>
<div class="mui-row">
<div class="mui-col-md-3">
<ul class="mui-tabs">
<li class="mui--is-active"><a data-mui-toggle="tab" data-mui-controls="pane-default-1">Суммарная статистика</a></li>
<li><a data-mui-toggle="tab" data-mui-controls="pane-default-2">Бои в составе клана</a></li>
<li><a data-mui-toggle="tab" data-mui-controls="pane-default-3">Бои в составе роты</a></li>
<li><a data-mui-toggle="tab" data-mui-controls="pane-default-5">Оборона Укрепрайона</a></li>
<li><a data-mui-toggle="tab" data-mui-controls="pane-default-6">Вылазки Укрепрайона</a></li>
</ul>
</div>
<div class="mui-col-md-9">
<div class="mui-tabs__pane mui--is-active" id="pane-default-1">
<h2>Суммарная статистика</h2>
<table class="mui-table mui-table--bordered">
{% for c in tank_stats.all %}
<tr>
<td>{{ texts_statistics['all'][c] }}</td>
<td>{{ tank_stats['all'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-2">
<h2>Бои в составе клана</h2>
<table class="mui-table mui-table--bordered">
{% for c in tank_stats.clan %}
<tr>
<td>{{ texts_statistics['clan'][c] }}</td>
<td>{{ tank_stats['clan'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-3">
<h2>Бои в составе роты</h2>
<table class="mui-table mui-table--bordered">
{% for c in tank_stats['company'] %}
<tr>
<td>{{ texts_statistics['company'][c] }}</td>
<td>{{ tank_stats['company'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-4">
<h2>Командные бои</h2>
<table class="mui-table mui-table--bordered">
{% for c in tank_stats['historical'] %}
<tr>
<td>{{ texts_statistics['historical'][c] }}</td>
<td>{{ tank_stats['historical'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-5">
<h2>Оборона Укрепрайона</h2>
<table class="mui-table mui-table--bordered">
{% for c in tank_stats['stronghold_defense'] %}
<tr>
<td>{{ texts_statistics['stronghold_defense'][c] }}</td>
<td>{{ tank_stats['stronghold_defense'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-6">
<h2>Вылазки Укрепрайона</h2>
<table class="mui-table mui-table--bordered">
{% for c in tank_stats['stronghold_skirmish'] %}
<tr>
<td>{{ texts_statistics['stronghold_skirmish'][c] }}</td>
<td>{{ tank_stats['stronghold_skirmish'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="mui-tabs__pane" id="pane-default-7">
<h2>Разное</h2>
<table class="mui-table mui-table--bordered">
<p>Поваленые деревья: {{tank_stats['trees_cut']}}
{% for c in tank_stats['flags'] %}
<tr>
<td>{{ texts_statistics['flags'][c] }}</td>
<td>{{ tank_stats['flags'][c] }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
{% endblock %}

View file

@ -1,9 +1,11 @@
{% extends "layouts/main.html" %} {% extends "layouts/main.html" %}
{% block title %}Create Profile{% endblock %} {% block title %}Вход{% endblock %}
{% block content %} {% block content %}
<h2>Sign in</h2> <h2>Вход</h2>
<form action="" method="post"> <form action="" method="post">
{% if error %}<p class=error><strong>Error:</strong> {{ error }}</p>{% endif %} {% if error %}
<p class=error><strong>Ошибка:</strong> {{ error }}</p>
{% endif %}
<p> <p>
<input type="hidden" name="openid" value="{{ config['WG_OPENID_URL'] }}"> <input type="hidden" name="openid" value="{{ config['WG_OPENID_URL'] }}">
<input type="submit" value="Wargaming OpenID" class="mui-btn mui-btn--primary mui-btn--raised"> <input type="submit" value="Wargaming OpenID" class="mui-btn mui-btn--primary mui-btn--raised">

View file

@ -0,0 +1,31 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h2>Турниры</h2>
<div class="mui-row">
<div class="mui-col-md-12">
<table class="mui-table mui-table--bordered">
<thead>
<tr>
<th>ID</th>
<th>Старт</th>
<th>Финиш</th>
<th>Ставка</th>
<th>Статус</th>
</tr>
</thead>
<tr>
<td>{{ rush.id }}</td>
<td>{{ rush.at_start }}</td>
<td>{{ rush.at_finish }}</td>
<td>{{ rush.bet }} рублей</td>
<td>{{ rush.status }}</td>
</tr>
</table>
<form action="{{ url_for('pages_rush.apply') }}" method="post">
<button class="mui-btn mui-btn--primary mui-btn--raised">Участвовать</button>
</form>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,95 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h2>Турниры</h2>
<div class="mui-row">
<div class="mui-col-md-12">
<table class="mui-table mui-table--bordered">
<thead>
<tr>
<th>ID</th>
<th>Старт</th>
<th>Финиш</th>
<th>Ставка</th>
<th>Статус</th>
</tr>
</thead>
{% for r in rush_list %}
{% if r.status == "preparation" %}
<tr>
<td>{{ r.id }}</td>
<td>{{ r.at_start }}</td>
<td>{{ r.at_finish }}</td>
<td>{{ r.bet }} рублей</td>
<td>{{ r.status }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
<div>
<h3>Участники</h3>
{% set allow_apply = 'true' %}
{% for u in rush_list_accounts %}
{% if u.account_id|int == account_id|int %}
{% set allow_apply = 'false' %}
{{ u.account_id }}
{% endif %}
{% endfor %}
</div>
{% if allow_apply == 'true' %}
<a href="{{ url_for('pages_rush.apply') }}" class="mui-btn mui-btn--primary mui-btn--raised">Участвовать</a>
{% else %}
<h3>Вы участвуете, вам необходимо совершить максимальное кол-во побед за время турнира</h3>
{% endif %}
</div>
<div class="mui-col-md-12">
<h3>Текущий</h3>
<table class="mui-table mui-table--bordered">
<thead>
<tr>
<th>ID</th>
<th>Старт</th>
<th>Финиш</th>
<th>Ставка</th>
<th>Статус</th>
</tr>
</thead>
{% for r in rush_list %}
{% if r.status == "started" %}
<tr>
<td>{{ r.id }}</td>
<td>{{ r.at_start }}</td>
<td>{{ r.at_finish }}</td>
<td>{{ r.bet }} рублей</td>
<td>{{ r.status }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
<h3>Завершены</h3>
<table class="mui-table mui-table--bordered">
<thead>
<tr>
<th>ID</th>
<th>Старт</th>
<th>Финиш</th>
<th>Ставка</th>
<th>Статус</th>
</tr>
</thead>
{% for r in rush_list %}
{% if r.status in ["finished", "canceled"] %}
<tr>
<td>{{ r.id }}</td>
<td>{{ r.at_start }}</td>
<td>{{ r.at_finish }}</td>
<td>{{ r.bet }} рублей</td>
<td>{{ r.status }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,66 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h2>Турниры</h2>
<div class="mui-row">
<div class="mui-col-md-12">
{% if account_balance < 100 %}
<div class="mui-row">
<div class="mui-col-md-12" style="background-color: red; color: white;">
<h1>Недостаточно денег в кошельке.</h1>
<h2>Необходимо пополнить кошелёк на 100 рублей для участия в турнире.</h2>
</div>
</div>
{% else %}
{% set allow_apply = 'true' %}
{% for u in rush_list_accounts %}
{% if u.account_id|int == account_id|int %}
{% set allow_apply = 'false' %}
{% endif %}
{% endfor %}
{% if allow_apply == 'true' %}
<div class="mui-row">
<div class="mui-col-md-12" style="background-color: green; color: white;">
<table class="mui-table mui-table--bordered" >
<thead>
<tr>
<th>ID</th>
<th>Старт</th>
<th>Финиш</th>
<th>Ставка</th>
<th>Статус</th>
</tr>
</thead>
{% for r in rush_list %}
{% if r.status == "preparation" %}
<tr>
<td>{{ r.id }}</td>
<td>{{ r.at_start }}</td>
<td>{{ r.at_finish }}</td>
<td>{{ r.bet }} рублей</td>
<td>{{ r.status }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
<a href="{{ url_for('pages_rush.apply') }}" class="mui-btn mui-btn--primary mui-btn--raised">Участвовать</a>
</div>
</div>
{% else %}
<div class="mui-row">
<div class="mui-col-md-12" style="background-color: black; color: white;">
<h3>Вы участвуете, вам необходимо совершить максимальное кол-во побед за время турнира</h3>
<p>Турнир начнется в полночь по московскому времени и закончится через 24 часа. Приз будет начислен победителю автоматически, сразу после окончания текущего турнира.</p>
<h4>Участники</h4>
{% for u in rush_list_accounts %}
{% if u.account_id|int == account_id|int %}
{{ u.account_id }}
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
{% endif %}
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,20 @@
<html>
<head></head>
<body>
<h1>Что-то пошло не так</h1>
<p>
Во время оплаты произошла ошибка, попробуйте ещё раз.
В случае повторения ошибки обратитесь в <a href="mailto:support@procdn.ru">поддержку</a>.
</p>
<ul>
<li><a href="{{ url_for('account.billing') }}">Биллинг</a></li>
{% if g.settings.get('SERVICE_CONTAINERS_ENABLE', "0") == "1" %}
<li><a href="{{ url_for('containers.index') }}">Контейнеры</a></li>
{% endif %}
{% if g.settings.get('SERVICE_VMS_ENABLE', '0') == '1' %}
<li><a href="{{ url_for('vms.index') }}">Виртуальные машины</a></li>
{% endif %}
</ul>
</body>
</html>

View file

@ -1,13 +1,16 @@
{% extends 'layouts/main.html' %} {% extends 'layouts/main.html' %}
{% block content %} {% block content %}
<h2>My Wallet</h2> <h2>Кошелёк</h2>
<p>Cash: $100500</p> <p>Баланс: {{ balance }} рублей</p>
<h2>Add Money</h2> <h2>Пополнить баланс</h2>
<form action="" method="post" class="mui-form"> <form action="{{ url_for('pages_wallet.robokassa', action='proccess') }}" method="post" class="mui-form">
<div class="mui-textfield"> <div class="mui-textfield">
<input type='text' name="" value="" placeholder="100" /> <input type='text' name="amount" value="" placeholder="100" />
</div> </div>
<input type='submit' value="pay" class="mui-btn mui-btn--raised" /> <input type='submit' value="Оплатить" class="mui-btn mui-btn--raised" />
</form> </form>
<h2>История</h2>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,31 @@
<html>
<head>
<title></title>
</head>
<body>
{% if g.robokassa.MODE == 0 or g.robokassa.MODE == "0" %}
<form method="post" action="http://test.robokassa.ru/Index.aspx">
{% else %}
<form method="post" action="https://merchant.roboxchange.com/Index.aspx" name="robokassa" id="robokassa">
{% endif %}
<input type="hidden" name="MrchLogin" value="{{ payment['login'] }}" />
<input type="hidden" name="OutSum" value="{{ payment['amount'] }}" />
<input type="hidden" name="InvId" value="{{ payment['payment_id'] }}" />
<input type="hidden" name="Desc" value="Пополнение баланса" />
<input type="hidden" name="SignatureValue" value="{{ payment['signature'] }}" />
<input type="submit" value="Оплатить" />
</form>
<script type="text/javascript">
window.onload=function(){
var auto = setTimeout(function(){ autoRefresh(); }, 100);
function submitform(){
document.forms["robokassa"].submit();
}
function autoRefresh(){
clearTimeout(auto);
auto = setTimeout(function(){ submitform(); autoRefresh(); }, 10000);
}
}
</script>
</body>
</html>

View file

@ -0,0 +1,8 @@
<html>
<head></head>
<body>
<h1>Успешная оплата</h1>
<p>Баланс успешно пополнен.</p>
<p><a href="{{ url_for("account.billing") }}">В личный кабинет</a></p>
</body>
</html>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Успешное пополнение счёта</title>
</head>
<body>
Спасибо!
Личный счёт успешно пополнен.
<ul>
<li><a href="{{ url_for('bills.index') }}">Биллинг</a></li>
{% if g.settings.get('SERVICE_CONTAINERS_ENABLE', "0") == "1" %}
<li><a href="{{ url_for('containers.index') }}">Контейнеры</a></li>
{% endif %}
{% if g.settings.get('SERVICE_VMS_ENABLE', '0') == '1' %}
<li><a href="{{ url_for('vms.index') }}">Виртуальные машины</a></li>
{% endif %}
</ul>
</body>
</html>

View file

@ -0,0 +1,7 @@
from .account import pages_account
from .home import pages_home
from .stats import pages_stats
from .wallet import pages_wallet
from .technic import pages_technic
from .achievements import pages_achievements
from .rush import pages_rush

View file

@ -1,3 +1,4 @@
# coding: utf-8
import requests import requests
from flask import ( from flask import (
g, Blueprint, render_template, abort, current_app, redirect, g, Blueprint, render_template, abort, current_app, redirect,
@ -9,44 +10,33 @@ from wotstats.openid import oid
from wotstats.log import log from wotstats.log import log
from wotstats.database import db from wotstats.database import db
from wotstats.models import User from wotstats.models import User
from wotstats.lib import parse_wargaming_openid_url from wotstats.lib import parse_wargaming_openid_url, get_player_personal_data, statistics as texts_statistics
pages_account = Blueprint('pages_account', __name__, url_prefix='/account', template_folder='templates') pages_account = Blueprint(
'pages_account', __name__,
def __get_player_personal_data(): url_prefix='/account',
log.debug(session) template_folder='templates'
user_id = parse_wargaming_openid_url(session['openid'])[0] )
url = "https://api.worldoftanks.ru/wot/account/info/"
payload = {
"application_id": current_app.config['WG_APPLICATION_ID'],
"account_id": user_id
}
__ = requests.get(url, params=payload).json()
return __.get('data', {}).get(user_id)
@pages_account.route('/') @pages_account.route('/')
def index(): def index():
from wotstats.tasks import hello
# from wotstats.tasks import *
hello.delay()
if not g.user: if not g.user:
return redirect(url_for('pages_home.index')) return redirect(url_for('pages_home.index'))
account_statistics = __get_player_personal_data() user_id = parse_wargaming_openid_url(session['openid'])[0]
account_statistics = get_player_personal_data(
current_app.config['WG_APPLICATION_ID'], user_id
)
return render_template( return render_template(
'pages/account/index.html', 'pages/account/index.html',
account_statistics=account_statistics) account_statistics=account_statistics,
texts_statistics=texts_statistics)
@pages_account.route('/statistics.html') @pages_account.route('/statistics.html')
def statistics(): def statistics():
if not g.user: if not g.user:
return redirect(url_for('pages_home.index')) return redirect(url_for('pages_home.index'))
return render_template('pages/account/statistics.html')
return render_template(
'pages/account/statistics.html')

View file

@ -0,0 +1,46 @@
import requests
from flask import (
g, Blueprint, render_template, abort, current_app, redirect,
redirect, request, url_for, session, flash, jsonify
)
from jinja2 import TemplateNotFound
from wotstats.openid import oid
from wotstats.log import log
from wotstats.database import db
from wotstats.models import User
from wotstats.lib import parse_wargaming_openid_url
pages_achievements = Blueprint(
'achievements', __name__, url_prefix='/achievements',
template_folder='templates')
def __get_achievements():
log.debug(session)
user_id = parse_wargaming_openid_url(session['openid'])[0]
url = "https://api.worldoftanks.ru/wot/account/achievements/"
payload = {
"application_id": current_app.config['WG_APPLICATION_ID'],
"account_id": user_id
}
__ = requests.get(url, params=payload).json()
return __.get('data', {}).get(user_id)
@pages_achievements.route('/')
def index():
"""Summary statistics"""
if not g.user:
return redirect(url_for('pages_home.index'))
# TODO: total accounts
#
account_achievements = __get_achievements()
return render_template(
'pages/account/achievements.html',
account_achievements=account_achievements
)

View file

@ -1,80 +1,89 @@
# coding: utf-8
import re import re
import requests import requests
import validator
from flask import ( from flask import (
g, Blueprint, render_template, abort, current_app, redirect, g, Blueprint, render_template, abort, current_app, redirect, redirect,
redirect, request, url_for, session, flash request, url_for, session, flash
) )
from jinja2 import TemplateNotFound from jinja2 import TemplateNotFound
from wotstats.openid import oid
from wotstats.openid import oid
from wotstats.database import db from wotstats.database import db
from wotstats.models import * from wotstats.models import *
from wotstats.lib import parse_wargaming_openid_url
# from wotstats.tasks import get_stats
pages_home = Blueprint('pages_home', __name__, template_folder='templates') pages_home = Blueprint('pages_home', __name__, template_folder='templates')
# def show(page): # TODO: add it after login
# try: # get_stats.delay()
# return render_template('pages/%s.html' % page)
# except TemplateNotFound:
# abort(404)
@pages_home.route('/', defaults={'page': 'index'}) @pages_home.route('/', defaults={'page': 'index'})
@pages_home.route('/<page>') @pages_home.route('/<page>')
def index(page): def index(page):
print session
return render_template('pages/index.html') return render_template('pages/index.html')
# @pages_home.route('/auth.html') @pages_home.route('/login', methods=['GET'])
# def auth_step1():
# return render_template('pages/auth_step1.html')
@pages_home.route('/login', methods=['GET', 'POST'])
@oid.loginhandler @oid.loginhandler
def login(): def login():
print request.form
print request.args print request.args
if g.user is not None: if g.user is not None:
return redirect(oid.get_next_url()) return redirect(oid.get_next_url())
if request.method == 'POST':
openid = request.form.get('openid')
if openid:
return oid.try_login(
openid,
ask_for=['email', 'nickname'],
ask_for_optional=['fullname'])
return render_template( return render_template(
'pages/login.html', 'pages/login.html',
next=oid.get_next_url(), next=oid.get_next_url(),
error=oid.fetch_error()) error=oid.fetch_error())
@pages_home.route('/create-profile', methods=['GET', 'POST']) @pages_home.route('/login', methods=['POST'])
@oid.loginhandler
def login_post():
if g.user is not None:
return redirect(oid.get_next_url())
openid = request.form.get('openid')
if not openid:
return redirect(url_for('home.login'))
return oid.try_login(
openid, ask_for=['email', 'nickname'], ask_for_optional=['fullname'])
@pages_home.route('/create-profile', methods=['GET'])
def create_profile(): def create_profile():
if g.user is not None or 'openid' not in session: if g.user is not None or 'openid' not in session:
return redirect(url_for('pages_home.index')) return redirect(url_for('pages_home.index'))
if request.method == 'POST':
name = request.form['name']
email = request.form['email']
if not name:
flash(u'Error: you have to provide a name')
elif '@' not in email:
flash(u'Error: you have to enter a valid email address')
else:
flash(u'Profile successfully created')
u = User(email)
u.name = name
u.openid = session['openid']
u.password = ''
db.session.add(u) return render_template('pages/create_profile.html', next=oid.get_next_url())
db.session.commit()
return redirect(oid.get_next_url())
return render_template( @pages_home.route('/create-profile', methods=['POST'])
'pages/create_profile.html', def create_profile_post():
next=oid.get_next_url()) if g.user is not None or 'openid' not in session:
return redirect(url_for('pages_home.index'))
name = request.form['name']
email = request.form['email']
if not name:
flash(u'Error: you have to provide a name')
if not validator.email(email):
flash(u'Error: you have to enter a valid email address')
return redirect(url_for('home.create_profile'))
flash(u'Profile successfully created')
u = User(email)
u.name = name
u.openid = session['openid']
u.password = ''
db.session.add(u)
db.session.commit()
return redirect(oid.get_next_url())
@pages_home.route('/logout') @pages_home.route('/logout')
@ -90,9 +99,11 @@ def logout():
def token(): def token():
print request.args print request.args
print request.form print request.form
print session
# if 'openid' not in session or 'user' in session:
# return redirect(url_for('pages_home.index'))
if 'openid' not in session or 'user' in session:
return redirect(url_for('pages_home.index'))
# ImmutableMultiDict([('status', u'ok'), ('access_token', u'a4d0a13df7c733102fbf6cd650794c6d047e91aa'), ('nickname', u'CrazyPants1999'), ('account_id', u'69552613'), ('', u'1505047809')]) # ImmutableMultiDict([('status', u'ok'), ('access_token', u'a4d0a13df7c733102fbf6cd650794c6d047e91aa'), ('nickname', u'CrazyPants1999'), ('account_id', u'69552613'), ('', u'1505047809')])
if request.args.get('status') == 'ok' and request.args.get('access_token'): if request.args.get('status') == 'ok' and request.args.get('access_token'):
token = UserWotTokens.query.filter_by(user=session['user']) token = UserWotTokens.query.filter_by(user=session['user'])
@ -117,11 +128,13 @@ def token():
} }
return redirect(oid.get_next_url()) return redirect(oid.get_next_url())
# redirect_url = 'http://truesoft.org:5000/token' url = current_app.config['WG_TOKEN_URL']
payload = {
response = requests.get('{}?application_id={}&nofollow=1&redirect_uri={}'.format( 'application_id': current_app.config['WG_APPLICATION_ID'],
current_app.config['WG_TOKEN_URL'], 'redirect_uri': current_app.config['WG_REDIRECT_URL'],
current_app.config['WG_APPLICATION_ID'], current_app.config['WG_REDIRECT_URL'])).json() 'nofollow': 1,
}
response = requests.get(url, params=payload).json()
if response.get('status') == 'ok': if response.get('status') == 'ok':
return redirect(response.get('data', {}).get('location')) return redirect(response.get('data', {}).get('location'))
@ -130,6 +143,9 @@ def token():
@oid.after_login @oid.after_login
def create_or_login(resp): def create_or_login(resp):
# resp
# 'aim', 'blog', 'country', 'date_of_birth', 'email', 'extensions', 'fullname', 'gender', 'icq', 'identity_url', 'image', 'jabber', 'language', 'month_of_birth', 'msn', 'nickname', 'phone', 'postcode', 'skype', 'timezone', 'website', 'yahoo', 'year_of_birth'
session['openid'] = resp.identity_url session['openid'] = resp.identity_url
session['token'] = None session['token'] = None
session['user'] = None session['user'] = None
@ -143,10 +159,25 @@ def create_or_login(resp):
name=resp.fullname or resp.nickname, name=resp.fullname or resp.nickname,
email=resp.email)) email=resp.email))
wot_account_id, wot_account_nickname = parse_wargaming_openid_url(resp.identity_url)
user_wot_account = WotAccounts.query.filter_by(account_id=wot_account_id).first()
if not user_wot_account:
x = WotAccounts(account_id=wot_account_id, nickname=wot_account_nickname)
x.user = user.id
db.session.add(x)
db.session.commit()
else:
if user_wot_account.user != user.id:
user_wot_account.user = user.id
db.session.commit()
session['user'] = user.id session['user'] = user.id
# flash(u'Successfully signed in') # flash(u'Successfully signed in')
g.user = user g.user = user
if not session['token']: print('session: {}'.format(session))
if session['token'] is None:
print('not token')
return redirect(url_for('pages_home.token')) return redirect(url_for('pages_home.token'))
return redirect(oid.get_next_url()) return redirect(oid.get_next_url())

73
wotstats/views/rush.py Normal file
View file

@ -0,0 +1,73 @@
import requests
from flask import (
g, Blueprint, render_template, abort, current_app, redirect,
redirect, request, url_for, session, flash
)
from jinja2 import TemplateNotFound
from wotstats.openid import oid
from wotstats.database import db
from wotstats.models import Rush, RushAccounts, WotAccounts, UserWallet
from wotstats.lib import parse_wargaming_openid_url
pages_rush = Blueprint(
'pages_rush', __name__,
url_prefix='/rush',
template_folder='templates')
@pages_rush.route('/')
def index():
if not g.user:
return redirect(url_for('pages_home.index'))
rush_list = Rush.query.all()
rush_preparation = Rush.query.filter(Rush.status == 'preparation').first()
rush_list_accounts = RushAccounts.query.filter(RushAccounts.rush_id == rush_preparation.id).all()
account_id, account_nickname = parse_wargaming_openid_url(session['openid'])
print(session)
ub = UserWallet.query.filter(UserWallet.user == session['user']).first()
return render_template(
'pages/rush/index.html',
rush_list=rush_list,
rush_list_accounts=rush_list_accounts,
account_id=account_id,
account_nickname=account_nickname,
account_balance=ub.balance
)
@pages_rush.route('/apply.html')
def apply():
if not g.user:
return redirect(url_for('pages_home.index'))
rush_prep = Rush.query.filter(Rush.status == 'preparation').first()
return render_template(
'pages/rush/apply.html',
rush=rush_prep
)
@pages_rush.route('/apply.html', methods=['POST'])
def apply_post():
if not g.user:
return redirect(url_for('pages_home.index'))
r = Rush.query.filter(Rush.status == 'preparation').first()
wa = WotAccounts.query.filter(WotAccounts.user == session['user']).first()
ra = RushAccounts(rush_id=r.id, account_id=wa.account_id)
ra.start_data = {}
ra.finish_data = {}
db.session.add(ra)
db.session.commit()
return redirect(url_for('pages_rush.apply'))

39
wotstats/views/stats.py Normal file
View file

@ -0,0 +1,39 @@
import requests
from flask import (
g, Blueprint, render_template, abort, current_app, redirect,
redirect, request, url_for, session, flash, jsonify
)
from jinja2 import TemplateNotFound
from wotstats.openid import oid
from wotstats.log import log
from wotstats.database import db
from wotstats.models import User
from wotstats.lib import parse_wargaming_openid_url, statistics as texts_statistics
pages_stats = Blueprint(
'stats', __name__, url_prefix='/stats', template_folder='templates')
@pages_stats.route('/')
def index():
"""Summary statistics"""
if not g.user:
return redirect(url_for('pages_home.index'))
# TODO: total accounts
#
account_statistics = __get_player_personal_data()
return render_template(
'pages/account/index.html',
account_statistics=account_statistics
)
@pages_stats.route('/summary.json')
def json_summary():
return jsonify()
@pages_stats.route('/account.json')
def json_account():
return jsonify()

164
wotstats/views/technic.py Normal file
View file

@ -0,0 +1,164 @@
import requests
from flask import (
g, Blueprint, render_template, abort, current_app, redirect,
redirect, request, url_for, session, flash, jsonify
)
from jinja2 import TemplateNotFound
from wotstats.openid import oid
from wotstats.log import log
from wotstats.database import db
from wotstats.models import User
from wotstats.lib import parse_wargaming_openid_url, get_player_personal_data, statistics as texts_statistics
from .technic_list import t
pages_technic = Blueprint(
'technic', __name__, url_prefix='/technic', template_folder='templates')
def __get_technic():
log.debug(session)
user_id = parse_wargaming_openid_url(session['openid'])[0]
g.wg_user_id = user_id
url = "https://api.worldoftanks.ru/wot/account/tanks/"
payload = {
"application_id": current_app.config['WG_APPLICATION_ID'],
"account_id": user_id
}
__ = requests.get(url, params=payload).json()
xx = __.get('data', {}).get(user_id)
return xx
def __get_technic_user_tank(tank_id):
# ?application_id=502910c1c785c3c7ca2e83c9e89bde02&account_id=69552613&tank_id=5121&r_realm=ru&run=1
# ?application_id=502910c1c785c3c7ca2e83c9e89bde02&account_id=69552613
user_id = parse_wargaming_openid_url(session['openid'])[0]
g.wg_user_id = user_id
url = "https://api.worldoftanks.ru/wot/tanks/stats/"
payload = {
"application_id": current_app.config['WG_APPLICATION_ID'],
"account_id": user_id,
"tank_id": tank_id,
}
__ = requests.get(url, params=payload).json()
return __.get('data', {}).get(user_id)
@pages_technic.route('/')
def index():
"""Summary statistics"""
if not g.user:
return redirect(url_for('pages_home.index'))
list_levels = []
print(request.args.getlist('level[]'))
if len(request.args.getlist('level[]')) > 0:
list_levels = []
for i in request.args.getlist('level[]'):
list_levels.append(int(i))
# TODO: total accounts
#
account_technic = list()
for x in __get_technic():
if len(list_levels) == 0:
x['details'] = t.get(str(x['tank_id']))
account_technic.append(x)
else:
if t.get(str(x['tank_id'])).get('level') in list_levels:
x['details'] = t.get(str(x['tank_id']))
account_technic.append(x)
order_keys = {
'level': lambda data: data['details'].get('level', 0),
'nation': lambda data: data['details']['nation'],
'type': lambda data: data['details']['type'],
'name': lambda data: data['details']['name_i18n'],
'battles': lambda data: data['statistics']['battles'],
'wins': lambda data: data['statistics']['wins'],
}
if request.args.get('order', 'level') in order_keys:
order = order_keys[request.args.get('order', 'level')]
else:
order = order_keys['level']
reverse = False if request.args.get('sort') == 'asc' else True
technic = sorted(account_technic, key=order, reverse=reverse)
return render_template(
'pages/account/technic.html',
account_technic=technic,
args={
'level': list_levels,
'sort': reverse,
'order': request.args.get('order', 'level'),
}
)
@pages_technic.route('/list.json')
def list_json():
if not g.user:
return redirect(url_for('pages_home.index'))
list_levels = []
print(request.args.getlist('level'))
if len(request.args.getlist('level')) > 0:
list_levels = []
for i in request.args.getlist('levelss'):
list_levels.append(int(i))
# TODO: total accounts
#
account_technic = list()
for x in __get_technic():
if len(list_levels) == 0:
x['details'] = t.get(str(x['tank_id']))
account_technic.append(x)
else:
if t.get(str(x['tank_id'])).get('level') in list_levels:
x['details'] = t.get(str(x['tank_id']))
account_technic.append(x)
order_keys = {
'level': lambda data: data['details']['level'],
'nation': lambda data: data['details']['nation'],
'type': lambda data: data['details']['type'],
'name': lambda data: data['details']['name_i18n'],
'battles': lambda data: data['statistics']['battles'],
'wins': lambda data: data['statistics']['wins'],
}
if request.args.get('order', 'level') in order_keys:
order = order_keys[request.args.get('order', 'level')]
else:
order = order_keys['level']
reverse = False if request.args.get('sort') == 'asc' else True
technic = sorted(account_technic, key=order, reverse=reverse)
return jsonify(technic=technic, levels=list_levels)
@pages_technic.route('/<int:user_id>/<int:tank_id>/')
def user_tech_stats(user_id, tank_id):
"""Summary statistics"""
if not g.user:
return redirect(url_for('pages_home.index'))
print(g.user)
# TODO: total accounts
#
tank_stats = __get_technic_user_tank(tank_id)
return render_template(
'pages/account/technic_user_tank.html',
tank_stats=tank_stats[0],
texts_statistics=texts_statistics,
)

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,7 @@
# coding: utf-8
from hashlib import md5
from datetime import datetime
import requests import requests
from flask import ( from flask import (
g, Blueprint, render_template, abort, current_app, redirect, g, Blueprint, render_template, abort, current_app, redirect,
@ -7,7 +11,7 @@ from jinja2 import TemplateNotFound
from wotstats.openid import oid from wotstats.openid import oid
from wotstats.database import db from wotstats.database import db
from wotstats.models import User from wotstats.models import User, UserWallet, UserWalletTransactions
from wotstats.lib import parse_wargaming_openid_url from wotstats.lib import parse_wargaming_openid_url
pages_wallet = Blueprint( pages_wallet = Blueprint(
@ -19,6 +23,134 @@ def index():
if not g.user: if not g.user:
return redirect(url_for('pages_home.index')) return redirect(url_for('pages_home.index'))
if UserWallet.query.filter_by(user=session['user']).count() == 0:
n = UserWallet(session['user'], 0)
db.session.add(n)
db.session.commit()
balance = UserWallet.query.with_entities(
UserWallet.balance
).filter_by(
user=session['user']
).scalar()
return render_template( return render_template(
'pages/wallet/index.html' 'pages/wallet/index.html',
balance=balance
) )
@pages_wallet.route('/robokassa/<action>', methods=['GET', 'POST'])
def robokassa(action):
print action
print request.form
if action == 'proccess':
if not g.user:
return redirect(url_for('pages_home.index'))
user_id = session['user']
amount = request.form.get('amount', 0)
# create transaction data to database
nt = UserWalletTransactions(user=user_id)
nt.amount = amount
nt.created_at = datetime.now()
# nt.method = 'robokassa'
nt.status = 'proccess'
db.session.add(nt)
db.session.commit()
transaction_id = nt.id
payment_details = {
"payment_id": transaction_id,
"amount": amount,
"login": current_app.config['ROBOKASSA']['LOGIN'],
"password": current_app.config['ROBOKASSA']['PASSWORD1'],
"signature": ''
}
payment_details["signature"] = md5(
"%(login)s:%(amount)s:%(payment_id)s:%(password)s" % payment_details
).hexdigest()
g.robokassa = current_app.config['ROBOKASSA']
# print payment_details
return render_template(
'pages/wallet/robokassa/process.html',
payment=payment_details
)
if action == 'result':
if request.method == 'POST':
transaction_id = request.form['InvId']
signature = request.form['SignatureValue']
amount = request.form['OutSum']
transaction_hash = md5("%s:%s:%s" % (
amount,
transaction_id,
current_app.config['ROBOKASSA']['PASSWORD2'])
).hexdigest()
# print transaction_hash
# print signature.lower()
if signature.lower() == transaction_hash.lower():
# update transaction signature
transaction = UserWalletTransactions.query.filter(
UserWalletTransactions.id == transaction_id
).first()
# # update transaction signature
# controller_robokassa.transaction_set_notified(transaction_id, 1)
# update user balance
# controller_robokassa.balance_update(transaction_id, amount)
uw = UserWallet.query.filter(UserWallet.id == transaction.user).first()
uw.balance += amount
transaction.status = 'success'
db.session.flush()
else:
return jsonify(error="invalid signature")
return render_template('pages/wallet/robokassa/result.html')
return redirect(url_for('account.billing'))
if action == 'success':
if not g.user:
return redirect(url_for('pages_home.index'))
if request.method == "POST":
# print request.form
# culture = request.form['Culture']
# transaction_id = request.form.get('InvId')
# TODO: если эта часть делается на шаге `results`, то можно убрать его
# update transaction signature
# transaction = models.UsersBalanceTransactions.get(models.UsersBalanceTransactions.id == transaction_id)
# transaction.status = 'success'
# transaction.save()
# TODO: redirect to success page
return redirect(url_for('pages_home.index'))
# TODO: redirect to success page
return redirect(url_for('pages_home.index'))
if action == 'fail':
if not g.user:
return redirect(url_for('pages_home.index'))
if request.method == "POST":
# print request.form
transaction_id = request.form['InvId']
# update transaction signature
transaction = UserWalletTransactions.query.filter(
UserWalletTransactions.id == transaction_id
).first()
transaction.status = 'fail'
db.session.flush()
# TODO: redirect to fail page
return redirect(url_for('pages_home.index'))