some party impl

This commit is contained in:
Evgenii Alekseev 2019-10-16 02:48:55 +03:00
parent 2d84459c4d
commit 4ff985bf81
13 changed files with 262 additions and 137 deletions

View File

@ -0,0 +1,75 @@
'''
party id
'''
import random
import string
from yoyo import step
__depends__ = {'20190830_01_sYYZL-init-tables', '20190910_01_tgBmx-users-table'}
party_id = ''.join(random.sample(string.ascii_letters, 16))
steps = [
step('''create table players2 (
party_id text not null,
player_id integer primary key,
created integer not null,
nick text not null,
job text not null,
bis_link text,
priority integer not null default 1
)'''),
# not safe for injections, but sqlite and psycopg have different placeholders for parameters
step('''insert into players2 select '%s' as party_id, players.* from players''' % (party_id,)),
step('''drop index if exists players_nick_job_idx'''),
step('''create unique index players_nick_job_idx on players2(party_id, nick, job)'''),
step('''create table loot2 (
loot_id integer primary key,
player_id integer not null,
created integer not null,
piece text not null,
is_tome integer not null,
foreign key (player_id) references players2(player_id) on delete cascade
)'''),
step('''insert into loot2 select * from loot'''),
step('''drop index if exists loot_owner_idx'''),
step('''create index loot_owner_idx on loot(player_id)'''),
step('''create table bis2 (
player_id integer not null,
created integer not null,
piece text not null,
is_tome integer not null,
foreign key (player_id) references players2(player_id) on delete cascade
)'''),
step('''insert into bis2 select * from bis'''),
step('''drop index if exists bis_piece_player_id_idx'''),
step('''create unique index bis_piece_player_id_idx on bis2(player_id, piece)'''),
step('''create table users2 (
party_id text not null,
user_id integer primary key,
username text not null,
password text not null,
permission text not null,
foreign key (party_id) references players2(party_id) on delete cascade
)'''),
# not safe for injections, but sqlite and psycopg have different placeholders for parameters
step('''insert into users2 select '%s' as party_id, users.* from users''' % (party_id,)),
step('''drop index if exists users_username_idx'''),
step('''create unique index users_username_idx on users2(party_id, username)'''),
step('''drop table users'''),
step('''alter table users2 rename to users'''),
step('''drop table loot'''),
step('''alter table loot2 rename to loot'''),
step('''drop table bis'''),
step('''alter table bis2 rename to bis'''),
step('''drop table players'''),
step('''alter table players2 rename to players''')
]

View File

@ -7,4 +7,4 @@ priority = is_required loot_count_bis loot_priority loot_count loot_count_total
[web]
host = 0.0.0.0
port = 8000
templates = templates
templates = /home/arcanis/Documents/github/ffxivbis/templates

View File

@ -8,7 +8,7 @@
#
from aiohttp.web import middleware, Request, Response
from aiohttp_security import AbstractAuthorizationPolicy, check_permission
from typing import Callable, Optional
from typing import Callable, Optional, Tuple
from ffxivbis.core.database import Database
@ -18,12 +18,19 @@ class AuthorizationPolicy(AbstractAuthorizationPolicy):
def __init__(self, database: Database) -> None:
self.database = database
def split_identity(self, identity: str) -> Tuple[str, str]:
# identity is party_id + username
party_id, username = identity.split('+')
return party_id, username
async def authorized_userid(self, identity: str) -> Optional[str]:
user = await self.database.get_user(identity)
return identity if user is not None else None
party_id, username = self.split_identity(identity)
user = await self.database.get_user(party_id, username)
return username if user is not None else None
async def permits(self, identity: str, permission: str, context: str = None) -> bool:
user = await self.database.get_user(identity)
party_id, username = self.split_identity(identity)
user = await self.database.get_user(party_id, username)
if user is None:
return False
if user.username != identity:

View File

@ -25,21 +25,21 @@ from .views.html.users import UsersHtmlView
def setup_routes(app: Application) -> None:
# api routes
app.router.add_delete('/admin/api/v1/login/{username}', LoginView)
app.router.add_post('/api/v1/login', LoginView)
app.router.add_post('/api/v1/logout', LogoutView)
app.router.add_put('/admin/api/v1/login', LoginView)
app.router.add_delete('/admin/api/v1/{party_id}/login/{username}', LoginView)
app.router.add_post('/api/v1/{party_id}/login', LoginView)
app.router.add_post('/api/v1/{party_id}/logout', LogoutView)
app.router.add_put('/admin/api/v1/{party_id}/login', LoginView)
app.router.add_get('/api/v1/party', PlayerView)
app.router.add_post('/api/v1/party', PlayerView)
app.router.add_get('/api/v1/party/{party_id}', PlayerView)
app.router.add_post('/api/v1/party/{party_id}', PlayerView)
app.router.add_get('/api/v1/party/bis', BiSView)
app.router.add_post('/api/v1/party/bis', BiSView)
app.router.add_put('/api/v1/party/bis', BiSView)
app.router.add_get('/api/v1/party/{party_id}/bis', BiSView)
app.router.add_post('/api/v1/party/{party_id}/bis', BiSView)
app.router.add_put('/api/v1/party/{party_id}/bis', BiSView)
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_get('/api/v1/party/{party_id}/loot', LootView)
app.router.add_post('/api/v1/party/{party_id}/loot', LootView)
app.router.add_put('/api/v1/party/{party_id}/loot', LootView)
# html routes
app.router.add_get('/', IndexHtmlView)
@ -48,19 +48,19 @@ def setup_routes(app: Application) -> None:
app.router.add_get('/api-docs', ApiHtmlView)
app.router.add_get('/api-docs/swagger.json', ApiDocVIew)
app.router.add_get('/party', PlayerHtmlView)
app.router.add_post('/party', PlayerHtmlView)
app.router.add_get('/party/{party_id}', PlayerHtmlView)
app.router.add_post('/party/{party_id}', PlayerHtmlView)
app.router.add_get('/bis', BiSHtmlView)
app.router.add_post('/bis', BiSHtmlView)
app.router.add_get('/bis/{party_id}', BiSHtmlView)
app.router.add_post('/bis/{party_id}', BiSHtmlView)
app.router.add_get('/loot', LootHtmlView)
app.router.add_post('/loot', LootHtmlView)
app.router.add_get('/loot/{party_id}', LootHtmlView)
app.router.add_post('/loot/{party_id}', LootHtmlView)
app.router.add_get('/suggest', LootSuggestHtmlView)
app.router.add_post('/suggest', LootSuggestHtmlView)
app.router.add_get('/suggest/{party_id}', LootSuggestHtmlView)
app.router.add_post('/suggest/{party_id}', LootSuggestHtmlView)
app.router.add_get('/admin/users', UsersHtmlView)
app.router.add_post('/admin/users', UsersHtmlView)
app.router.add_get('/admin/users/{party_id}', UsersHtmlView)
app.router.add_post('/admin/users/{party_id}', UsersHtmlView)

View File

@ -126,12 +126,13 @@ class LoginView(LoginBaseView, OpenApi):
except Exception:
data = dict(await self.request.post())
required = ['username', 'password']
required = ['username', 'password', 'party_id']
if any(param not in data for param in required):
return wrap_invalid_param(required, data)
try:
await self.create_user(data['username'], data['password'], data.get('permission', 'get'))
await self.create_user(data['party_id'], data['username'],
data['password'], data.get('permission', 'get'))
except Exception as e:
self.request.app.logger.exception('cannot create user')
return wrap_exception(e, data)

View File

@ -21,8 +21,8 @@ class LoginBaseView(View):
return False
return md5_crypt.verify(password, user.password)
async def create_user(self, username: str, password: str, permission: str) -> None:
await self.request.app['database'].insert_user(User(username, password, permission), False)
async def create_user(self, party_id: str, username: str, password: str, permission: str) -> None:
await self.request.app['database'].insert_user(party_id, User(username, password, permission), False)
async def login(self, username: str, password: str) -> None:
if await self.check_credentials(username, password):

View File

@ -16,8 +16,7 @@ from aiohttp_security import CookiesIdentityPolicy
from ffxivbis.core.config import Configuration
from ffxivbis.core.database import Database
from ffxivbis.core.loot_selector import LootSelector
from ffxivbis.core.party import Party
from ffxivbis.core.party_aggregator import PartyAggregator
from .auth import AuthorizationPolicy, authorize_factory
from .routes import setup_routes
@ -35,7 +34,7 @@ def run_server(app: web.Application) -> None:
port=app['config'].getint('web', 'port'),
handle_signals=False)
def setup_service(config: Configuration, database: Database, loot: LootSelector, party: Party) -> web.Application:
def setup_service(config: Configuration, database: Database, aggregator: PartyAggregator) -> web.Application:
app = web.Application(logger=logging.getLogger('http'))
app.on_shutdown.append(on_shutdown)
@ -62,10 +61,7 @@ def setup_service(config: Configuration, database: Database, loot: LootSelector,
app.logger.info('setup database')
app['database'] = database
app.logger.info('setup loot selector')
app['loot'] = loot
app.logger.info('setup party worker')
app['party'] = party
app.logger.info('setup aggregator')
app['aggregator'] = aggregator
return app

View File

@ -12,9 +12,7 @@ import logging
from ffxivbis.api.web import run_server, setup_service
from ffxivbis.core.config import Configuration
from ffxivbis.core.database import Database
from ffxivbis.core.loot_selector import LootSelector
from ffxivbis.core.party import Party
from ffxivbis.models.user import User
from ffxivbis.core.party_aggregator import PartyAggregator
class Application:
@ -29,13 +27,7 @@ class Application:
database = loop.run_until_complete(Database.get(self.config))
database.migration()
party = loop.run_until_complete(Party.get(database))
aggregator = PartyAggregator(self.config, database)
admin = User(self.config.get('auth', 'root_username'), self.config.get('auth', 'root_password'), 'admin')
loop.run_until_complete(database.insert_user(admin, True))
priority = self.config.get('settings', 'priority').split()
loot_selector = LootSelector(party, priority)
web = setup_service(self.config, database, loot_selector, party)
web = setup_service(self.config, database, aggregator)
run_server(web)

View File

@ -59,40 +59,43 @@ class Database:
async def init(self) -> None:
pass
async def delete_piece(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
async def delete_piece(self, party_id: str, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
raise NotImplementedError
async def delete_piece_bis(self, player_id: PlayerId, piece: Piece) -> None:
async def delete_piece_bis(self, party_id: str, player_id: PlayerId, piece: Piece) -> None:
raise NotImplementedError
async def delete_player(self, player_id: PlayerId) -> None:
async def delete_player(self, party_id: str, player_id: PlayerId) -> None:
raise NotImplementedError
async def delete_user(self, username: str) -> None:
async def delete_user(self, party_id: str, username: str) -> None:
raise NotImplementedError
async def get_party(self) -> List[Player]:
async def get_party(self, party_id: str) -> List[Player]:
raise NotImplementedError
async def get_player(self, player_id: PlayerId) -> Optional[int]:
async def get_player(self, party_id: str, player_id: PlayerId) -> Optional[int]:
raise NotImplementedError
async def get_user(self, username: str) -> Optional[User]:
async def get_players(self, party_id: str) -> List[int]:
raise NotImplementedError
async def get_users(self) -> List[User]:
async def get_user(self, party_id: str, username: str) -> Optional[User]:
raise NotImplementedError
async def insert_piece(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
async def get_users(self, party_id: str) -> List[User]:
raise NotImplementedError
async def insert_piece_bis(self, player_id: PlayerId, piece: Piece) -> None:
async def insert_piece(self, party_id: str, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
raise NotImplementedError
async def insert_player(self, player: Player) -> None:
async def insert_piece_bis(self, party_id: str, player_id: PlayerId, piece: Piece) -> None:
raise NotImplementedError
async def insert_user(self, user: User, hashed_password: bool) -> None:
async def insert_player(self, party_id: str, player: Player) -> None:
raise NotImplementedError
async def insert_user(self, party_id: str, user: User, hashed_password: bool) -> None:
raise NotImplementedError
def migration(self) -> None:

View File

@ -20,8 +20,9 @@ from .database import Database
class Party:
def __init__(self, database: Database) -> None:
def __init__(self, party_id: str, database: Database) -> None:
self.lock = Lock()
self.party_id = party_id
self.players: Dict[PlayerId, Player] = {}
self.database = database
@ -31,9 +32,9 @@ class Party:
return list(self.players.values())
@classmethod
async def get(cls: Type[Party], database: Database) -> Party:
obj = Party(database)
players = await database.get_party()
async def get(cls: Type[Party], party_id: str, database: Database) -> Party:
obj = cls(party_id, database)
players = await database.get_party(party_id)
for player in players:
obj.players[player.player_id] = player
return obj
@ -42,28 +43,28 @@ class Party:
with self.lock:
player = self.players[player_id]
player.link = link
await self.database.insert_player(player)
await self.database.insert_player(self.party_id, player)
async def remove_player(self, player_id: PlayerId) -> Optional[Player]:
await self.database.delete_player(player_id)
await self.database.delete_player(self.party_id, player_id)
with self.lock:
player = self.players.pop(player_id, None)
return player
async def set_player(self, player: Player) -> PlayerId:
player_id = player.player_id
await self.database.insert_player(player)
await self.database.insert_player(self.party_id, player)
with self.lock:
self.players[player_id] = player
return player_id
async def set_item(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
await self.database.insert_piece(player_id, piece)
await self.database.insert_piece(self.party_id, player_id, piece)
with self.lock:
self.players[player_id].loot.append(piece)
async def remove_item(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
await self.database.delete_piece(player_id, piece)
await self.database.delete_piece(self.party_id, player_id, piece)
with self.lock:
try:
self.players[player_id].loot.remove(piece)
@ -71,11 +72,11 @@ class Party:
pass
async def set_item_bis(self, player_id: PlayerId, piece: Piece) -> None:
await self.database.insert_piece_bis(player_id, piece)
await self.database.insert_piece_bis(self.party_id, player_id, piece)
with self.lock:
self.players[player_id].bis.set_item(piece)
async def remove_item_bis(self, player_id: PlayerId, piece: Piece) -> None:
await self.database.delete_piece_bis(player_id, piece)
await self.database.delete_piece_bis(self.party_id, player_id, piece)
with self.lock:
self.players[player_id].bis.remove_item(piece)

View File

@ -0,0 +1,26 @@
#
# 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 .config import Configuration
from .database import Database
from .loot_selector import LootSelector
from .party import Party
class PartyAggregator:
def __init__(self, config: Configuration, database: Database) -> None:
self.config = config
self.database = database
async def get_party(self, party_id: str) -> Party:
return await Party.get(party_id, self.database)
async def get_loot_selector(self, party: Party) -> LootSelector:
priority = self.config.get('settings', 'priority').split()
return LootSelector(party, priority)

View File

@ -42,8 +42,8 @@ class PostgresDatabase(Database):
self.pool = await asyncpg.create_pool(host=self.host, port=self.port, username=self.username,
password=self.password, database=self.database)
async def delete_piece(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
player = await self.get_player(player_id)
async def delete_piece(self, party_id: str, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
player = await self.get_player(party_id, player_id)
if player is None:
return
@ -57,8 +57,8 @@ class PostgresDatabase(Database):
player, piece.name, getattr(piece, 'is_tome', True)
)
async def delete_piece_bis(self, player_id: PlayerId, piece: Piece) -> None:
player = await self.get_player(player_id)
async def delete_piece_bis(self, party_id: str, player_id: PlayerId, piece: Piece) -> None:
player = await self.get_player(party_id, player_id)
if player is None:
return
@ -67,24 +67,29 @@ class PostgresDatabase(Database):
'''delete from bis where player_id = $1 and piece = $2''',
player, piece.name)
async def delete_player(self, player_id: PlayerId) -> None:
async def delete_player(self, party_id: str, player_id: PlayerId) -> None:
async with self.pool.acquire() as conn:
await conn.execute('''delete from players where nick = $1 and job = $2''',
player_id.nick, player_id.job.name)
await conn.execute('''delete from players where nick = $1 and job = $2 and party_id = $3''',
player_id.nick, player_id.job.name, party_id)
async def delete_user(self, username: str) -> None:
async def delete_user(self, party_id: str, username: str) -> None:
async with self.pool.acquire() as conn:
await conn.execute('''delete from users where username = $1''', username)
await conn.execute('''delete from users where username = $1 and party_id = $2''',
(username, party_id))
async def get_party(self, party_id: str) -> List[Player]:
players = await self.get_players(party_id)
if not players:
return []
async def get_party(self) -> List[Player]:
async with self.pool.acquire() as conn:
rows = await conn.fetch('''select * from bis''')
rows = await conn.fetch('''select * from bis where player_id in $1''', players)
bis_pieces = [Loot(row['player_id'], Piece.get(row)) for row in rows]
rows = await conn.fetch('''select * from loot''')
rows = await conn.fetch('''select * from loot where player_id in $1''', players)
loot_pieces = [Loot(row['player_id'], Piece.get(row)) for row in rows]
rows = await conn.fetch('''select * from players''')
rows = await conn.fetch('''select * from players where party_id = $1''', party_id)
party = {
row['player_id']: Player(Job[row['job']], row['nick'], BiS(), [], row['bis_link'], row['priority'])
for row in rows
@ -92,24 +97,30 @@ class PostgresDatabase(Database):
return self.set_loot(party, bis_pieces, loot_pieces)
async def get_player(self, player_id: PlayerId) -> Optional[int]:
async def get_player(self, party_id: str, player_id: PlayerId) -> Optional[int]:
async with self.pool.acquire() as conn:
player = await conn.fetchrow('''select player_id from players where nick = $1 and job = $2''',
player_id.nick, player_id.job.name)
player = await conn.fetchrow('''select player_id from players where nick = $1 and job = $2 and party_id = $3''',
player_id.nick, player_id.job.name, party_id)
return player['player_id'] if player is not None else None
async def get_user(self, username: str) -> Optional[User]:
async def get_players(self, party_id: str) -> List[int]:
async with self.pool.acquire() as conn:
user = await conn.fetchrow('''select * from users where username = $1''', username)
players = await conn.fetch('''select player_id from players where party_id = $1''', (party_id,))
return [player['player_id'] for player in players]
async def get_user(self, party_id: str, username: str) -> Optional[User]:
async with self.pool.acquire() as conn:
user = await conn.fetchrow('''select * from users where username = $1 and party_id = $2''',
username, party_id)
return User(user['username'], user['password'], user['permission']) if user is not None else None
async def get_users(self) -> List[User]:
async def get_users(self, party_id: str) -> List[User]:
async with self.pool.acquire() as conn:
users = await conn.fetch('''select * from users''')
users = await conn.fetch('''select * from users where party_id = $1''', party_id)
return [User(user['username'], user['password'], user['permission']) for user in users]
async def insert_piece(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
player = await self.get_player(player_id)
async def insert_piece(self, party_id: str, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
player = await self.get_player(party_id, player_id)
if player is None:
return
@ -122,8 +133,8 @@ class PostgresDatabase(Database):
Database.now(), piece.name, getattr(piece, 'is_tome', True), player
)
async def insert_piece_bis(self, player_id: PlayerId, piece: Piece) -> None:
player = await self.get_player(player_id)
async def insert_piece_bis(self, party_id: str, player_id: PlayerId, piece: Piece) -> None:
player = await self.get_player(party_id, player_id)
if player is None:
return
@ -138,27 +149,27 @@ class PostgresDatabase(Database):
Database.now(), piece.name, piece.is_tome, player
)
async def insert_player(self, player: Player) -> None:
async def insert_player(self, party_id: str, player: Player) -> None:
async with self.pool.acquire() as conn:
await conn.execute(
'''insert into players
(created, nick, job, bis_link, priority)
(party_id, created, nick, job, bis_link, priority)
values
($1, $2, $3, $4, $5)
($1, $2, $3, $4, $5, $6)
on conflict on constraint players_nick_job_idx do update set
created = $1, bis_link = $4, priority = $5''',
Database.now(), player.nick, player.job.name, player.link, player.priority
Database.now(), player.nick, player.job.name, player.link, player.priority, party_id
)
async def insert_user(self, user: User, hashed_password: bool) -> None:
async def insert_user(self, party_id: str, user: User, hashed_password: bool) -> None:
password = user.password if hashed_password else md5_crypt.hash(user.password)
async with self.pool.acquire() as conn:
await conn.execute(
'''insert into users
(username, password, permission)
(party_id, username, password, permission)
values
($1, $2, $3)
($1, $2, $3, $4)
on conflict on constraint users_username_idx do update set
password = $2, permission = $3''',
user.username, password, user.permission
party_id, user.username, password, user.permission
)

View File

@ -31,8 +31,8 @@ class SQLiteDatabase(Database):
def connection(self) -> str:
return f'sqlite:///{self.database_path}'
async def delete_piece(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
player = await self.get_player(player_id)
async def delete_piece(self, party_id: str, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
player = await self.get_player(party_id, player_id)
if player is None:
return
@ -45,8 +45,8 @@ class SQLiteDatabase(Database):
)''',
(player, piece.name, getattr(piece, 'is_tome', True)))
async def delete_piece_bis(self, player_id: PlayerId, piece: Piece) -> None:
player = await self.get_player(player_id)
async def delete_piece_bis(self, party_id: str, player_id: PlayerId, piece: Piece) -> None:
player = await self.get_player(party_id, player_id)
if player is None:
return
@ -55,26 +55,32 @@ class SQLiteDatabase(Database):
'''delete from bis where player_id = ? and piece = ?''',
(player, piece.name))
async def delete_player(self, player_id: PlayerId) -> None:
async def delete_player(self, party_id: str, player_id: PlayerId) -> None:
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute('''delete from players where nick = ? and job = ?''',
(player_id.nick, player_id.job.name))
await cursor.execute('''delete from players where nick = ? and job = ? and party_id = ?''',
(player_id.nick, player_id.job.name, party_id))
async def delete_user(self, username: str) -> None:
async def delete_user(self, party_id: str, username: str) -> None:
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute('''delete from users where username = ?''', (username,))
await cursor.execute('''delete from users where username = ? and party_id = ?''',
(username, party_id))
async def get_party(self, party_id: str) -> List[Player]:
players = await self.get_players(party_id)
if not players:
return []
placeholder = ', '.join(['?'] * len(players))
async def get_party(self) -> List[Player]:
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute('''select * from bis''')
await cursor.execute('''select * from bis where player_id in ({})'''.format(placeholder), players)
rows = await cursor.fetchall()
bis_pieces = [Loot(row['player_id'], Piece.get(row)) for row in rows]
await cursor.execute('''select * from loot''')
await cursor.execute('''select * from loot where player_id in ({})'''.format(placeholder), players)
rows = await cursor.fetchall()
loot_pieces = [Loot(row['player_id'], Piece.get(row)) for row in rows]
await cursor.execute('''select * from players''')
await cursor.execute('''select * from players where party_id = ?''', (party_id,))
rows = await cursor.fetchall()
party = {
row['player_id']: Player(Job[row['job']], row['nick'], BiS(), [], row['bis_link'], row['priority'])
@ -83,27 +89,34 @@ class SQLiteDatabase(Database):
return self.set_loot(party, bis_pieces, loot_pieces)
async def get_player(self, player_id: PlayerId) -> Optional[int]:
async def get_player(self, party_id: str, player_id: PlayerId) -> Optional[int]:
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute('''select player_id from players where nick = ? and job = ?''',
(player_id.nick, player_id.job.name))
await cursor.execute('''select player_id from players where nick = ? and job = ? and party_id = ?''',
(player_id.nick, player_id.job.name, party_id))
player = await cursor.fetchone()
return player['player_id'] if player is not None else None
async def get_user(self, username: str) -> Optional[User]:
async def get_players(self, party_id: str) -> List[int]:
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute('''select * from users where username = ?''', (username,))
await cursor.execute('''select player_id from players where party_id = ?''', (party_id,))
players = await cursor.fetchall()
return [player['player_id'] for player in players]
async def get_user(self, party_id: str, username: str) -> Optional[User]:
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute('''select * from users where username = ? and party_id = ?''',
(username, party_id))
user = await cursor.fetchone()
return User(user['username'], user['password'], user['permission']) if user is not None else None
async def get_users(self) -> List[User]:
async def get_users(self, party_id: str) -> List[User]:
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute('''select * from users''')
await cursor.execute('''select * from users where party_id = ?''', (party_id,))
users = await cursor.fetchall()
return [User(user['username'], user['password'], user['permission']) for user in users]
async def insert_piece(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
player = await self.get_player(player_id)
async def insert_piece(self, party_id: str, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
player = await self.get_player(party_id, player_id)
if player is None:
return
@ -116,8 +129,8 @@ class SQLiteDatabase(Database):
(Database.now(), piece.name, getattr(piece, 'is_tome', True), player)
)
async def insert_piece_bis(self, player_id: PlayerId, piece: Piece) -> None:
player = await self.get_player(player_id)
async def insert_piece_bis(self, party_id: str, player_id: PlayerId, piece: Piece) -> None:
player = await self.get_player(party_id, player_id)
if player is None:
return
@ -130,23 +143,23 @@ class SQLiteDatabase(Database):
(Database.now(), piece.name, piece.is_tome, player)
)
async def insert_player(self, player: Player) -> None:
async def insert_player(self, party_id: str, player: Player) -> None:
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute(
'''replace into players
(created, nick, job, bis_link, priority)
(party_id, created, nick, job, bis_link, priority)
values
(?, ?, ?, ?, ?)''',
(Database.now(), player.nick, player.job.name, player.link, player.priority)
(?, ?, ?, ?, ?, ?)''',
(party_id, Database.now(), player.nick, player.job.name, player.link, player.priority)
)
async def insert_user(self, user: User, hashed_password: bool) -> None:
async def insert_user(self, party_id: str, user: User, hashed_password: bool) -> None:
password = user.password if hashed_password else md5_crypt.hash(user.password)
async with SQLiteHelper(self.database_path) as cursor:
await cursor.execute(
'''replace into users
(username, password, permission)
(party_id, username, password, permission)
values
(?, ?, ?)''',
(user.username, password, user.permission)
(?, ?, ?, ?)''',
(party_id, user.username, password, user.permission)
)