This commit is contained in:
161
admidio/model.py
Normal file
161
admidio/model.py
Normal file
@ -0,0 +1,161 @@
|
||||
"""High-levle api."""
|
||||
|
||||
import logging
|
||||
from datetime import date
|
||||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
|
||||
from typing import Final
|
||||
from .db import AdmidioDB
|
||||
|
||||
|
||||
MEMBER_ROLE = "Member"
|
||||
FIELD_PAID_DATE = "PMB_PAID"
|
||||
FIELD_FEE = "PMB_FEE"
|
||||
FIELD_DUEDATE = "PMB_DUEDATE"
|
||||
FIELD_EMAIL = "SYS_EMAIL"
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class AdmidioDBSettings:
|
||||
"""Database settings class."""
|
||||
|
||||
user: str
|
||||
password: str
|
||||
host: str
|
||||
database: str
|
||||
port: int = 3306
|
||||
|
||||
|
||||
class AdmidioMemberFee:
|
||||
"""Admidio member fee manager."""
|
||||
|
||||
def __init__(self, user_id: int, connection: AdmidioDBSettings) -> None:
|
||||
"""Create member fee manager class."""
|
||||
self.db: AdmidioDB = AdmidioDB(
|
||||
connection.user,
|
||||
connection.password,
|
||||
connection.host,
|
||||
connection.database,
|
||||
connection.port,
|
||||
)
|
||||
self.user_id: Final = user_id
|
||||
self._user_data: dict[str, str] | None = None
|
||||
|
||||
@property
|
||||
def is_member(self) -> bool:
|
||||
"""Check if user is a member."""
|
||||
role_ids = self.db.get_user_roles(self.user_id)
|
||||
role_map = self.db.get_roles()
|
||||
roles = [role_map[role_id] for role_id in role_ids]
|
||||
return MEMBER_ROLE in roles
|
||||
|
||||
@property
|
||||
def member_fee(self) -> int:
|
||||
"""Get membership fee."""
|
||||
roles = self.db.get_roles()
|
||||
member_role_id = next(
|
||||
iter(
|
||||
[
|
||||
role_id
|
||||
for role_id, role_name in roles.items()
|
||||
if role_name == MEMBER_ROLE
|
||||
]
|
||||
)
|
||||
)
|
||||
role_payments = self.db.get_role_payments()
|
||||
fee = role_payments.get(member_role_id)
|
||||
if not fee:
|
||||
raise RuntimeError("Error: No membership cost set on Member role.")
|
||||
return int(fee)
|
||||
|
||||
@property
|
||||
def user_data(self) -> dict[str, str]:
|
||||
"""Get user data."""
|
||||
if not self._user_data:
|
||||
self._user_data = self._get_user_data()
|
||||
return self._user_data
|
||||
|
||||
def _get_user_data(self) -> dict[str, str]:
|
||||
"""Get user data."""
|
||||
user_fields = self.db.get_custom_fields()
|
||||
user_field_ids = {value: key for key, value in user_fields.items()}
|
||||
adm_user_data = self.db.get_adm_user_data(self.user_id)
|
||||
user_data: dict[str, str] = {}
|
||||
for field_id, data in adm_user_data.items():
|
||||
if field_name := user_field_ids.get(field_id):
|
||||
user_data[field_name] = data
|
||||
else:
|
||||
LOG.warning("Could not find a field definition for %s", field_id)
|
||||
return user_data
|
||||
|
||||
def _lookup_user_field(self, name: str) -> int:
|
||||
"""Lookup the ID of a user field."""
|
||||
user_fields = self.db.get_custom_fields()
|
||||
field_id = user_fields.get(name)
|
||||
if not field_id:
|
||||
raise RuntimeError(f"Unable to find field ID for field {name}")
|
||||
return field_id
|
||||
|
||||
@property
|
||||
def last_paid(self) -> date | None:
|
||||
"""Get the date of last payment."""
|
||||
paid_data = self.user_data.get(FIELD_PAID_DATE)
|
||||
if not paid_data:
|
||||
return None
|
||||
paid_date = date.fromisoformat(paid_data)
|
||||
return paid_date
|
||||
|
||||
@property
|
||||
def has_paid(self) -> bool:
|
||||
"""Check if a user has paid."""
|
||||
if not self.last_paid:
|
||||
return False
|
||||
paid_days = date.today() - self.last_paid
|
||||
if paid_days.days > 365:
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def amount_due(self) -> int:
|
||||
"""Get amount due."""
|
||||
if fee := self.user_data.get(FIELD_FEE):
|
||||
return int(fee)
|
||||
if not self.is_member:
|
||||
raise RuntimeError(
|
||||
"User does not seem to be a member, and has no due fees."
|
||||
)
|
||||
return self.member_fee
|
||||
|
||||
def register_payment(self, amount_paid: int | None = None) -> None:
|
||||
"""Register payment,"""
|
||||
date_field = self._lookup_user_field(FIELD_PAID_DATE)
|
||||
amount_field = self._lookup_user_field(FIELD_FEE)
|
||||
date_paid = date.today().isoformat()
|
||||
if not amount_paid:
|
||||
amount_paid = self.member_fee
|
||||
self.db.create_user_data(self.user_id, date_field, date_paid)
|
||||
self.db.create_user_data(self.user_id, amount_field, str(amount_paid))
|
||||
|
||||
@classmethod
|
||||
def lookup_email(
|
||||
cls, email: str, settings: AdmidioDBSettings
|
||||
) -> "AdmidioMemberFee | None":
|
||||
"""Create instance by lookup up user email address."""
|
||||
db = AdmidioDB(
|
||||
settings.user,
|
||||
settings.password,
|
||||
settings.host,
|
||||
settings.database,
|
||||
settings.port,
|
||||
)
|
||||
fields = db.get_custom_fields()
|
||||
email_field_id = fields.get(FIELD_EMAIL)
|
||||
if not email_field_id:
|
||||
raise RuntimeError("Could not resolve email address field in database.")
|
||||
if user_id := db.get_user_id_by_field(email_field_id, email):
|
||||
return cls(user_id, settings)
|
||||
|
||||
return None
|
||||
Reference in New Issue
Block a user