mirror of
https://github.com/arcan1s/ffxivbis.git
synced 2025-04-24 17:27:17 +00:00
postgres demo support
This commit is contained in:
parent
98b20a073a
commit
c11103a5ba
13
README.md
13
README.md
@ -109,7 +109,7 @@ Service which allows to manage savage loot distribution easy.
|
||||
|
||||
* `include`: path to include configuration directory, string, optional.
|
||||
* `logging`: path to logging configuration, see `logging.ini` for reference, string, optional.
|
||||
* `database`: database provide name, string, required. Allowed values: `sqlite`.
|
||||
* `database`: database provide name, string, required. Allowed values: `sqlite`, `postgres`.
|
||||
* `priority`: methods of `Player` class which will be called to sort players for loot priority, space separated list of strings, required.
|
||||
|
||||
* `ariyala` section
|
||||
@ -129,6 +129,17 @@ Service which allows to manage savage loot distribution easy.
|
||||
* `root_username`: username of administrator, string, required.
|
||||
* `root_password`: md5 hashed password of administrator, string, required.
|
||||
|
||||
* `postgres` section
|
||||
|
||||
Database settings for `postgres` provider.
|
||||
|
||||
* `database`: database name, string, required.
|
||||
* `host`: database host, string, required.
|
||||
* `password`: database password, string, required.
|
||||
* `port`: database port, int, required.
|
||||
* `username`: database username, string, required.
|
||||
* `migrations_path`: path to database migrations, string, required.
|
||||
|
||||
* `sqlite` section
|
||||
|
||||
Database settings for `sqlite` provider.
|
||||
|
5
TODO.md
5
TODO.md
@ -1,2 +1,3 @@
|
||||
[ ] postgres support
|
||||
[ ] pretty UI
|
||||
* [ ] items improvements
|
||||
* [ ] multiple parties support
|
||||
* [ ] pretty UI
|
3
setup.py
3
setup.py
@ -28,7 +28,6 @@ setup(
|
||||
'aiohttp',
|
||||
'aiohttp_jinja2',
|
||||
'aiohttp_security',
|
||||
'aiosqlite',
|
||||
'Jinja2',
|
||||
'passlib',
|
||||
'requests',
|
||||
@ -44,6 +43,8 @@ setup(
|
||||
include_package_data=True,
|
||||
|
||||
extras_require={
|
||||
'Postgresql': ['aiopg'],
|
||||
'SQLite': ['aiosqlite'],
|
||||
'test': ['coverage', 'pytest'],
|
||||
},
|
||||
)
|
||||
|
@ -26,7 +26,7 @@ class Application:
|
||||
def run(self) -> None:
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
database = Database.get(self.config)
|
||||
database = loop.run_until_complete(Database.get(self.config))
|
||||
database.migration()
|
||||
|
||||
party = loop.run_until_complete(Party.get(database))
|
||||
|
@ -35,22 +35,30 @@ class Database:
|
||||
return int(datetime.datetime.now().timestamp())
|
||||
|
||||
@classmethod
|
||||
def get(cls: Type[Database], config: Configuration) -> Database:
|
||||
async def get(cls: Type[Database], config: Configuration) -> Database:
|
||||
database_type = config.get('settings', 'database')
|
||||
database_settings = config.get_section(database_type)
|
||||
|
||||
if database_type == 'sqlite':
|
||||
from .sqlite import SQLiteDatabase
|
||||
obj: Type[Database] = SQLiteDatabase
|
||||
elif database_type == 'postgres':
|
||||
from .postgres import PostgresDatabase
|
||||
obj = PostgresDatabase
|
||||
else:
|
||||
raise InvalidDatabase(database_type)
|
||||
|
||||
return obj(**database_settings)
|
||||
database = obj(**database_settings)
|
||||
await database.init()
|
||||
return database
|
||||
|
||||
@property
|
||||
def connection(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
async def init(self) -> None:
|
||||
pass
|
||||
|
||||
async def delete_piece(self, player_id: PlayerId, piece: Union[Piece, Upgrade]) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
166
src/service/core/postgres.py
Normal file
166
src/service/core/postgres.py
Normal file
@ -0,0 +1,166 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
import asyncpg
|
||||
|
||||
from passlib.hash import md5_crypt
|
||||
from psycopg2.extras import DictCursor
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from service.models.bis import BiS
|
||||
from service.models.job import Job
|
||||
from service.models.loot import Loot
|
||||
from service.models.piece import Piece
|
||||
from service.models.player import Player, PlayerId
|
||||
from service.models.upgrade import Upgrade
|
||||
from service.models.user import User
|
||||
|
||||
from .database import Database
|
||||
|
||||
|
||||
class PostgresDatabase(Database):
|
||||
|
||||
def __init__(self, host: str, port: int, username: str, password: str, database: str, migrations_path: str) -> None:
|
||||
Database.__init__(self, migrations_path)
|
||||
self.host = host
|
||||
self.port = int(port)
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.database = database
|
||||
self.pool: asyncpg.pool.Pool = None # type: ignore
|
||||
|
||||
@property
|
||||
def connection(self) -> str:
|
||||
return 'postgresql://{username}:{password}@{host}:{port}/{database}'.format(
|
||||
username=self.username, password=self.password, host=self.host, port=self.port, database=self.database
|
||||
)
|
||||
|
||||
async def init(self) -> None:
|
||||
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)
|
||||
if player is None:
|
||||
return
|
||||
|
||||
async with self.pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
'''delete from loot
|
||||
where loot_id in (
|
||||
select loot_id from loot
|
||||
where player_id = $1 and piece = $2 and is_tome = $3 order by created desc limit 1
|
||||
)''',
|
||||
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)
|
||||
if player is None:
|
||||
return
|
||||
|
||||
async with self.pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
'''delete from bis where player_id = $1 and piece = $2''',
|
||||
player, piece.name)
|
||||
|
||||
async def delete_player(self, 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)
|
||||
|
||||
async def delete_user(self, username: str) -> None:
|
||||
async with self.pool.acquire() as conn:
|
||||
await conn.execute('''delete from users where username = $1''', username)
|
||||
|
||||
async def get_party(self) -> List[Player]:
|
||||
async with self.pool.acquire() as conn:
|
||||
rows = await conn.fetch('''select * from bis''')
|
||||
bis_pieces = [Loot(row['player_id'], Piece.get(row)) for row in rows]
|
||||
|
||||
rows = await conn.fetch('''select * from loot''')
|
||||
loot_pieces = [Loot(row['player_id'], Piece.get(row)) for row in rows]
|
||||
|
||||
rows = await conn.fetch('''select * from players''')
|
||||
party = {
|
||||
row['player_id']: Player(Job[row['job']], row['nick'], BiS(), [], row['bis_link'], row['priority'])
|
||||
for row in rows
|
||||
}
|
||||
|
||||
return self.set_loot(party, bis_pieces, loot_pieces)
|
||||
|
||||
async def get_player(self, 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)
|
||||
return player['player_id'] if player is not None else None
|
||||
|
||||
async def get_user(self, username: str) -> Optional[User]:
|
||||
async with self.pool.acquire() as conn:
|
||||
user = await conn.fetchrow('''select * from users where username = $1''', username)
|
||||
return User(user['username'], user['password'], user['permission']) if user is not None else None
|
||||
|
||||
async def get_users(self) -> List[User]:
|
||||
async with self.pool.acquire() as conn:
|
||||
users = await conn.fetch('''select * from users''')
|
||||
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)
|
||||
if player is None:
|
||||
return
|
||||
|
||||
async with self.pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
'''insert into loot
|
||||
(created, piece, is_tome, player_id)
|
||||
values
|
||||
($1, $2, $3, $4)''',
|
||||
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)
|
||||
if player is None:
|
||||
return
|
||||
|
||||
async with self.pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
'''insert into bis
|
||||
(created, piece, is_tome, player_id)
|
||||
values
|
||||
($1, $2, $3, $4)
|
||||
on conflict on constraint bis_piece_player_id_idx do update set
|
||||
created = $1, is_tome = $3''',
|
||||
Database.now(), piece.name, piece.is_tome, player
|
||||
)
|
||||
|
||||
async def insert_player(self, player: Player) -> None:
|
||||
async with self.pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
'''insert into players
|
||||
(created, nick, job, bis_link, priority)
|
||||
values
|
||||
($1, $2, $3, $4, $5)
|
||||
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
|
||||
)
|
||||
|
||||
async def insert_user(self, 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)
|
||||
values
|
||||
($1, $2, $3)
|
||||
on conflict on constraint users_username_idx do update set
|
||||
password = $2, permission = $3''',
|
||||
user.username, password, user.permission
|
||||
)
|
Loading…
Reference in New Issue
Block a user