artemis/core/data/schema/card.py

136 lines
4.7 KiB
Python
Raw Normal View History

from typing import Dict, List, Optional
from sqlalchemy import Table, Column, UniqueConstraint
from sqlalchemy.types import Integer, String, Boolean, TIMESTAMP
2024-03-22 16:22:07 +00:00
from sqlalchemy.sql.schema import ForeignKey
from sqlalchemy.sql import func
from sqlalchemy.engine import Row
from core.data.schema.base import BaseData, metadata
aime_card = Table(
2023-03-09 16:38:58 +00:00
"aime_card",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
2023-03-09 16:38:58 +00:00
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("access_code", String(20)),
Column("created_date", TIMESTAMP, server_default=func.now()),
Column("last_login_date", TIMESTAMP, onupdate=func.now()),
Column("is_locked", Boolean, server_default="0"),
Column("is_banned", Boolean, server_default="0"),
UniqueConstraint("user", "access_code", name="aime_card_uk"),
2023-03-09 16:38:58 +00:00
mysql_charset="utf8mb4",
)
2023-03-09 16:38:58 +00:00
class CardData(BaseData):
2024-03-23 06:01:06 +00:00
async def get_card_by_access_code(self, access_code: str) -> Optional[Row]:
sql = aime_card.select(aime_card.c.access_code == access_code)
2024-03-23 06:01:06 +00:00
result = await self.execute(sql)
2023-03-09 16:38:58 +00:00
if result is None:
return None
return result.fetchone()
2024-03-23 06:01:06 +00:00
async def get_card_by_id(self, card_id: int) -> Optional[Row]:
sql = aime_card.select(aime_card.c.id == card_id)
2024-03-23 06:01:06 +00:00
result = await self.execute(sql)
2023-03-09 16:38:58 +00:00
if result is None:
return None
return result.fetchone()
2023-03-09 16:38:58 +00:00
2024-03-23 06:01:06 +00:00
async def update_access_code(self, old_ac: str, new_ac: str) -> None:
2023-03-09 16:38:58 +00:00
sql = aime_card.update(aime_card.c.access_code == old_ac).values(
access_code=new_ac
)
2024-03-23 06:01:06 +00:00
result = await self.execute(sql)
2023-03-09 16:38:58 +00:00
if result is None:
self.logger.error(
f"Failed to change card access code from {old_ac} to {new_ac}"
)
2024-03-23 06:01:06 +00:00
async def get_user_id_from_card(self, access_code: str) -> Optional[int]:
"""
Given a 20 digit access code as a string, get the user id associated with that card
"""
2024-03-23 06:01:06 +00:00
card = await self.get_card_by_access_code(access_code)
2023-03-09 16:38:58 +00:00
if card is None:
return None
return int(card["user"])
2023-03-09 16:38:58 +00:00
2024-03-23 06:01:06 +00:00
async def get_card_banned(self, access_code: str) -> Optional[bool]:
"""
Given a 20 digit access code as a string, check if the card is banned
"""
2024-03-23 06:01:06 +00:00
card = await self.get_card_by_access_code(access_code)
if card is None:
return None
if card["is_banned"]:
return True
return False
2024-03-23 06:01:06 +00:00
async def get_card_locked(self, access_code: str) -> Optional[bool]:
"""
Given a 20 digit access code as a string, check if the card is locked
"""
2024-03-23 06:01:06 +00:00
card = await self.get_card_by_access_code(access_code)
if card is None:
return None
if card["is_locked"]:
return True
return False
2024-03-23 06:01:06 +00:00
async def delete_card(self, card_id: int) -> None:
sql = aime_card.delete(aime_card.c.id == card_id)
2024-03-23 06:01:06 +00:00
result = await self.execute(sql)
2023-03-09 16:38:58 +00:00
if result is None:
self.logger.error(f"Failed to delete card with id {card_id}")
2024-03-23 06:01:06 +00:00
async def get_user_cards(self, aime_id: int) -> Optional[List[Row]]:
"""
Returns all cards owned by a user
"""
sql = aime_card.select(aime_card.c.user == aime_id)
2024-03-23 06:01:06 +00:00
result = await self.execute(sql)
2023-03-09 16:38:58 +00:00
if result is None:
return None
return result.fetchall()
2024-03-23 06:01:06 +00:00
async def create_card(self, user_id: int, access_code: str) -> Optional[int]:
"""
Given a aime_user id and a 20 digit access code as a string, create a card and return the ID if successful
"""
sql = aime_card.insert().values(user=user_id, access_code=access_code)
2024-03-23 06:01:06 +00:00
result = await self.execute(sql)
2023-03-09 16:38:58 +00:00
if result is None:
return None
return result.lastrowid
2024-03-23 06:01:06 +00:00
async def update_card_last_login(self, access_code: str) -> None:
sql = aime_card.update(aime_card.c.access_code == access_code).values(
last_login_date=func.now()
)
result = await self.execute(sql)
if result is None:
self.logger.warn(f"Failed to update last login time for {access_code}")
def to_access_code(self, luid: str) -> str:
"""
Given a felica cards internal 16 hex character luid, convert it to a 0-padded 20 digit access code as a string
"""
return f"{int(luid, base=16):0{20}}"
def to_idm(self, access_code: str) -> str:
"""
Given a 20 digit access code as a string, return the 16 hex character luid
"""
2023-03-09 16:38:58 +00:00
return f"{int(access_code):0{16}x}"