some html implementation

This commit is contained in:
2019-09-08 03:06:31 +03:00
parent 52a3c7fee7
commit 9bd51d9267
18 changed files with 425 additions and 13 deletions

View File

@ -11,9 +11,13 @@ from aiohttp.web import Application
from service.api.views.api.bis import BiSView
from service.api.views.api.loot import LootView
from service.api.views.api.player import PlayerView
from service.api.views.html.bis import BiSHtmlView
from service.api.views.html.index import IndexHtmlView
from service.api.views.html.player import PlayerHtmlView
def setup_routes(app: Application) -> None:
# api routes
app.router.add_get('/api/v1/party', PlayerView)
app.router.add_post('/api/v1/party', PlayerView)
@ -23,4 +27,13 @@ def setup_routes(app: Application) -> None:
app.router.add_get('/api/v1/party/loot', LootView)
app.router.add_post('/api/v1/party/loot', LootView)
app.router.add_put('/api/v1/party/loot', LootView)
app.router.add_put('/api/v1/party/loot', LootView)
# html routes
app.router.add_get('/', IndexHtmlView)
app.router.add_get('/party', PlayerHtmlView)
app.router.add_post('/party', PlayerHtmlView)
app.router.add_get('/bis', BiSHtmlView)
app.router.add_post('/bis', BiSHtmlView)

View File

@ -21,7 +21,7 @@ class PlayerView(PlayerBaseView):
party = self.player_get(self.request.query.getone('nick', None))
except Exception as e:
self.request.app.logger.exception('could not get loot')
self.request.app.logger.exception('could not get party')
return wrap_exception(e, self.request.query)
return wrap_json(party, self.request.query)

View File

@ -22,7 +22,7 @@ class PlayerBaseView(View):
player_id = player.player_id
self.request.app['party'].set_player(player)
if link is not None:
if link:
parser = AriyalaParser(self.request.app['config'])
items = parser.get(link)
for piece in items:

View File

@ -0,0 +1,80 @@
#
# Copyright (c) 2019 Evgeniy Alekseev.
#
# This file is part of ffxivbis
# (see https://github.com/arcan1s/ffxivbis).
#
# License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause
#
from aiohttp.web import HTTPFound, Response
from aiohttp_jinja2 import template
from typing import Any, Dict, List
from service.models.job import Job
from service.models.piece import Piece
from service.models.player import PlayerId
from service.api.utils import wrap_exception, wrap_invalid_param, wrap_json
from service.api.views.common.bis_base import BiSBaseView
from service.api.views.common.player_base import PlayerBaseView
class BiSHtmlView(BiSBaseView, PlayerBaseView):
@template('bis.jinja2')
async def get(self) -> Dict[str, Any]:
items: List[Dict[str, str]] = []
error = None
try:
players = self.player_get(None)
items = [
{
'player': player.player_id.pretty_name,
'piece': piece.name,
'is_tome': 'yes' if piece.is_tome else 'no'
}
for player in players
for piece in player.bis.pieces
]
except Exception as e:
self.request.app.logger.exception('could not get bis')
error = repr(e)
return {
'pieces': Piece.available(),
'players': items,
'request_error': error
}
async def post(self) -> Response:
data = await self.request.post()
required = ['method', 'player']
if any(param not in data for param in required):
return wrap_invalid_param(required, data)
try:
method = data.get('method')
player_id = PlayerId.from_pretty_name(data.get('player'))
if method == 'post':
required = ['action', 'piece']
if any(param not in data for param in required):
return wrap_invalid_param(required, data)
self.bis_post(data.get('action'), player_id,
Piece.get({'piece': data.get('piece'), 'is_tome': data.get('is_tome', False)}))
elif method == 'put':
required = ['bis']
if any(param not in data for param in required):
return wrap_invalid_param(required, data)
self.bis_put(player_id, data.get('bis'))
except Exception as e:
self.request.app.logger.exception('could not manage bis')
return wrap_exception(e, data)
return HTTPFound(self.request.url)

View File

@ -0,0 +1,18 @@
#
# Copyright (c) 2019 Evgeniy Alekseev.
#
# This file is part of ffxivbis
# (see https://github.com/arcan1s/ffxivbis).
#
# License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause
#
from aiohttp.web import View
from aiohttp_jinja2 import template
from typing import Any, Dict
class IndexHtmlView(View):
@template('index.jinja2')
async def get(self) -> Dict[str, Any]:
return {}

View File

@ -0,0 +1,66 @@
#
# Copyright (c) 2019 Evgeniy Alekseev.
#
# This file is part of ffxivbis
# (see https://github.com/arcan1s/ffxivbis).
#
# License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause
#
from aiohttp.web import HTTPFound, Response
from aiohttp_jinja2 import template
from typing import Any, Dict, List
from service.models.job import Job
from service.models.player import PlayerIdWithCounters
from service.api.utils import wrap_exception, wrap_invalid_param
from service.api.views.common.player_base import PlayerBaseView
class PlayerHtmlView(PlayerBaseView):
@template('party.jinja2')
async def get(self) -> Dict[str, Any]:
counters: List[PlayerIdWithCounters] = []
error = None
try:
party = self.player_get(None)
counters = [player.player_id_with_counters(None) for player in party]
except Exception as e:
self.request.app.logger.exception('could not get party')
error = repr(e)
return {
'players': [
{
'job': player.job.name,
'nick': player.nick,
'loot_count_bis': player.loot_count_bis,
'loot_count': player.loot_count,
'priority': player.priority
}
for player in counters
],
'request_error': error
}
async def post(self) -> Response:
data = await self.request.post()
required = ['action', 'job', 'nick']
if any(param not in data for param in required):
return wrap_invalid_param(required, data)
try:
action = data.get('action')
priority = data.get('priority', 0)
link = data.get('bis', None)
self.player_post(action, Job[data['job'].upper()], data['nick'], link, priority)
except Exception as e:
self.request.app.logger.exception('could not manage players')
return wrap_exception(e, data)
return HTTPFound(self.request.url)

View File

@ -6,6 +6,8 @@
#
# License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause
#
import aiohttp_jinja2
import jinja2
import logging
from aiohttp import web
@ -38,6 +40,8 @@ def setup_service(config: Configuration, database: Database, loot: LootSelector,
# routes
app.logger.info('setup routes')
setup_routes(app)
if config.has_option('web', 'templates'):
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader(config.get('web', 'templates')))
app.logger.info('setup configuration')
app['config'] = config

View File

@ -9,7 +9,7 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Mapping, Type, Union
from typing import Any, List, Mapping, Type, Union
from .upgrade import Upgrade
@ -33,11 +33,19 @@ class Piece:
return Upgrade.GearUpgrade
return Upgrade.NoUpgrade
@staticmethod
def available() -> List[str]:
return [
'weapon',
'head', 'body', 'hands', 'waist', 'legs', 'feet',
'ears', 'neck', 'wrist', 'left_ring', 'right_ring'
]
@classmethod
def get(cls: Type[Piece], data: Mapping[str, Any]) -> Union[Piece, Upgrade]:
try:
piece_type = data['piece']
is_tome = bool(data['is_tome'])
is_tome = data['is_tome'] in ('yes', 'on', '1', 1, True)
except KeyError:
raise InvalidDataRow(data)
if piece_type.lower() == 'weapon':

View File

@ -6,8 +6,12 @@
#
# License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause
#
from __future__ import annotations
import re
from dataclasses import dataclass
from typing import List, Optional, Union
from typing import List, Optional, Type, Union
from .bis import BiS
from .job import Job
@ -20,12 +24,22 @@ class PlayerId:
job: Job
nick: str
@property
def pretty_name(self) -> str:
return '{} ({})'.format(self.nick, self.job.name)
@classmethod
def from_pretty_name(cls: Type[PlayerId], value: str) -> PlayerId:
matches = re.search('^(?P<nick>.*) \((?P<job>[A-Z]+)\)$', value)
return PlayerId(Job[matches.group('job')], matches.group('nick'))
def __hash__(self) -> int:
return hash(str(self))
@dataclass
class PlayerIdWithCounters(PlayerId):
priority: int
loot_count: int
loot_count_bis: int
loot_count_total: int
@ -50,12 +64,15 @@ class Player:
def player_id(self) -> PlayerId:
return PlayerId(self.job, self.nick)
def player_id_with_counters(self, piece: Union[Piece, Upgrade]) -> PlayerIdWithCounters:
return PlayerIdWithCounters(self.job, self.nick, self.loot_count(piece),
def player_id_with_counters(self, piece: Union[Piece, Upgrade, None]) -> PlayerIdWithCounters:
return PlayerIdWithCounters(self.job, self.nick, self.priority, self.loot_count(piece),
self.loot_count_bis(piece), self.loot_count_total(piece))
# ordering methods
def is_required(self, piece: Union[Piece, Upgrade]) -> bool:
def is_required(self, piece: Union[Piece, Upgrade, None]) -> bool:
if piece is None:
return False
# lets check if it is even in bis
if not self.bis.has_piece(piece):
return False
@ -68,14 +85,16 @@ class Player:
return self.bis.upgrades_required[piece] > self.loot_count(piece)
return False
def loot_count(self, piece: Union[Piece, Upgrade]) -> int:
def loot_count(self, piece: Union[Piece, Upgrade, None]) -> int:
if piece is None:
return len(self.loot)
return self.loot.count(piece)
def loot_count_bis(self, _: Union[Piece, Upgrade]) -> int:
def loot_count_bis(self, _: Union[Piece, Upgrade, None]) -> int:
return len([piece for piece in self.loot if self.bis.has_piece(piece)])
def loot_count_total(self, _: Union[Piece, Upgrade]) -> int:
def loot_count_total(self, _: Union[Piece, Upgrade, None]) -> int:
return len(self.loot)
def loot_priority(self, _: Union[Piece, Upgrade]) -> int:
def loot_priority(self, _: Union[Piece, Upgrade, None]) -> int:
return self.priority