Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/model/blockchain/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pyright: reportUnusedImport=false
"""
Copyright BOOSTRY Co., Ltd.

Expand Down
981 changes: 609 additions & 372 deletions app/model/blockchain/token.py

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions app/model/db/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pyright: reportUnusedImport=false
"""
Copyright BOOSTRY Co., Ltd.

Expand Down
28 changes: 28 additions & 0 deletions app/model/db/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
"""

from datetime import UTC, datetime
from zoneinfo import ZoneInfo

from sqlalchemy import DateTime, create_engine
from sqlalchemy.dialects.mysql import DATETIME as MySQLDATETIME
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

from app import config, log

local_tz = ZoneInfo(config.TZ)

LOG = log.get_logger()

URI = config.DATABASE_URL
Expand Down Expand Up @@ -53,3 +56,28 @@ class Base(DeclarativeBase):
modified: Mapped[datetime | None] = mapped_column(
DateTime, default=naive_utcnow, onupdate=naive_utcnow
)

@staticmethod
def replace_to_local_tz(_datetime: datetime) -> datetime:
"""Convert timestamp from UTC to local timezone
:param _datetime:
:return: datetime
"""
datetime_local = _datetime.replace(tzinfo=UTC).astimezone(local_tz)
return datetime_local

@staticmethod
def format_timestamp(_datetime: datetime) -> str:
"""Convert timestamp from UTC to local timezone str
:param _datetime:
:return: str
"""
datetime_local = _datetime.replace(tzinfo=UTC).astimezone(local_tz)
return "{}/{:02d}/{:02d} {:02d}:{:02d}:{:02d}".format(
datetime_local.year,
datetime_local.month,
datetime_local.day,
datetime_local.hour,
datetime_local.minute,
datetime_local.second,
)
29 changes: 1 addition & 28 deletions app/model/db/idx_lock_unlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,15 @@
SPDX-License-Identifier: Apache-2.0
"""

from datetime import datetime, timedelta, timezone
from datetime import datetime
from enum import StrEnum
from zoneinfo import ZoneInfo

from pydantic import BaseModel
from sqlalchemy import JSON, BigInteger, Boolean, DateTime, String
from sqlalchemy.orm import Mapped, mapped_column

from app.config import TZ
from app.model.db.base import Base

UTC = timezone(timedelta(hours=0), "UTC")
local_tz = ZoneInfo(TZ)


class LockMessage(StrEnum):
garnishment = "garnishment"
Expand Down Expand Up @@ -86,17 +81,6 @@ class IDXLock(Base):
# Whether the lock is forced or not
is_forced: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)

@staticmethod
def replace_to_local_tz(_datetime: datetime) -> datetime | None:
"""Convert timestamp from UTC to local timezone
:param _datetime:
:return: datetime | None
"""
if _datetime is None:
return None
datetime_local = _datetime.replace(tzinfo=UTC).astimezone(local_tz)
return datetime_local

def json(self):
return {
"id": self.id,
Expand Down Expand Up @@ -151,17 +135,6 @@ class IDXUnlock(Base):
# Whether the unlock is forced or not
is_forced: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)

@staticmethod
def replace_to_local_tz(_datetime: datetime) -> datetime | None:
"""Convert timestamp from UTC to local timezone
:param _datetime:
:return: datetime | None
"""
if _datetime is None:
return None
datetime_local = _datetime.replace(tzinfo=UTC).astimezone(local_tz)
return datetime_local

def json(self):
return {
"id": self.id,
Expand Down
4 changes: 2 additions & 2 deletions app/model/db/idx_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"""

import datetime
from typing import Type, Union
from typing import Any, Mapping, Type, Union

from sqlalchemy import JSON, BigInteger, Boolean, DateTime, Float, Numeric, String, Text
from sqlalchemy.orm import Mapped, mapped_column
Expand Down Expand Up @@ -67,7 +67,7 @@ class TokenBase(Base):
# Cached time of short-term cache
short_term_cache_created: Mapped[datetime.datetime | None] = mapped_column(DateTime)

def json(self):
def json(self) -> Mapping[str, Any]:
return {
"token_address": self.token_address,
"token_template": self.token_template,
Expand Down
21 changes: 2 additions & 19 deletions app/model/db/idx_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
SPDX-License-Identifier: Apache-2.0
"""

from datetime import datetime, timedelta, timezone
from datetime import timedelta, timezone
from enum import StrEnum
from typing import Literal
from zoneinfo import ZoneInfo
Expand Down Expand Up @@ -87,25 +87,8 @@ class IDXTransfer(Base):
# => "ibet_wst_bridge"
message: Mapped[str | None] = mapped_column(String(50), index=True)

@staticmethod
def format_timestamp(_datetime: datetime) -> str:
"""Convert timestamp from UTC to local timezone str
:param _datetime:
:return: str
"""
if _datetime is None:
return ""
datetime_local = _datetime.replace(tzinfo=UTC).astimezone(local_tz)
return "{}/{:02d}/{:02d} {:02d}:{:02d}:{:02d}".format(
datetime_local.year,
datetime_local.month,
datetime_local.day,
datetime_local.hour,
datetime_local.minute,
datetime_local.second,
)

def json(self):
assert self.created is not None
return {
"transaction_hash": self.transaction_hash,
"token_address": self.token_address,
Expand Down
2 changes: 1 addition & 1 deletion app/model/db/idx_transfer_approval.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class IDXTransferApproval(Base):
transfer_approved: Mapped[bool | None] = mapped_column(Boolean)

@staticmethod
def format_datetime(_datetime: datetime) -> str:
def format_datetime(_datetime: datetime | None) -> str:
"""Convert timestamp from UTC to local timezone str
:param _datetime:
:return: str
Expand Down
19 changes: 1 addition & 18 deletions app/model/db/listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,8 @@ class Listing(Base):
def __repr__(self):
return "<Listing id='%d'>" % self.id

@staticmethod
def format_timestamp(_datetime: datetime) -> str:
"""Convert timestamp from UTC to local timezone str
:param _datetime:
:return: str
"""
if _datetime is None:
return ""
datetime_local = _datetime.replace(tzinfo=UTC).astimezone(local_tz)
return "{}/{:02d}/{:02d} {:02d}:{:02d}:{:02d}".format(
datetime_local.year,
datetime_local.month,
datetime_local.day,
datetime_local.hour,
datetime_local.minute,
datetime_local.second,
)

def json(self):
assert self.created is not None
return {
"id": self.id,
"token_address": self.token_address,
Expand Down
21 changes: 2 additions & 19 deletions app/model/db/public_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
SPDX-License-Identifier: Apache-2.0
"""

from datetime import datetime, timedelta, timezone
from datetime import timedelta, timezone
from typing import Literal
from zoneinfo import ZoneInfo

Expand Down Expand Up @@ -81,25 +81,8 @@ class PublicAccountList(Base):
# Account Address
account_address: Mapped[str] = mapped_column(String(42), nullable=False)

@staticmethod
def format_timestamp(_datetime: datetime) -> str:
"""Convert timestamp from UTC to local timezone str
:param _datetime:
:return: str
"""
if _datetime is None:
return ""
datetime_local = _datetime.replace(tzinfo=UTC).astimezone(local_tz)
return "{}/{:02d}/{:02d} {:02d}:{:02d}:{:02d}".format(
datetime_local.year,
datetime_local.month,
datetime_local.day,
datetime_local.hour,
datetime_local.minute,
datetime_local.second,
)

def json(self):
assert self.modified is not None
return {
"key_manager": self.key_manager,
"key_manager_name": self.key_manager_name,
Expand Down
1 change: 1 addition & 0 deletions app/model/mail/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pyright: reportUnusedImport=false
"""
Copyright BOOSTRY Co., Ltd.

Expand Down
4 changes: 2 additions & 2 deletions app/model/mail/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ def send_mail(self):

elif SMTP_METHOD == 1: # Amazon SES
# Initialize a new smtp client
smtp_client = boto3.client("ses", region_name=self.aws_region_name)
ses_client = boto3.client("ses", region_name=self.aws_region_name)

# Send mail
smtp_client.send_raw_email(
ses_client.send_raw_email(
Source=self.sender_email,
Destinations=[self.to_email],
RawMessage={
Expand Down
1 change: 1 addition & 0 deletions app/model/schema/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pyright: reportUnusedImport=false
"""
Copyright BOOSTRY Co., Ltd.

Expand Down
1 change: 1 addition & 0 deletions app/model/schema/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pyright: reportUnusedImport=false
"""
Copyright BOOSTRY Co., Ltd.

Expand Down
19 changes: 14 additions & 5 deletions app/model/schema/base/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,24 @@
from pydantic import (
AfterValidator,
BaseModel,
ConfigDict,
Field,
NonNegativeInt,
constr,
StringConstraints,
)

from app.model.type.base import EthereumAddress

############################
# COMMON
############################
EmailStr = constr(
pattern=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$", max_length=100
)
EmailStr = Annotated[
str,
StringConstraints(
pattern=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$",
max_length=100,
),
]

NaiveUTCDatetime = Annotated[datetime, Timezone(None)]

Expand Down Expand Up @@ -246,11 +251,15 @@ class Success200MetaModel(BaseModel):
Data = TypeVar("Data")


class EmptyData(BaseModel):
model_config = ConfigDict(extra="forbid")


class SuccessResponse(BaseModel):
meta: Success200MetaModel = Field(
..., examples=[Success200MetaModel(code=200, message="OK").model_dump()]
)
data: dict = {}
data: EmptyData = Field(default_factory=EmptyData)

@staticmethod
def default():
Expand Down
2 changes: 1 addition & 1 deletion app/model/schema/bc_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class TxDataDetail(BaseModel):
to_address: Optional[EthereumAddress]
contract_name: Optional[str]
contract_function: Optional[str]
contract_parameters: Optional[dict]
contract_parameters: Optional[dict[str, object]]
gas: NonNegativeInt
gas_price: NonNegativeInt
value: NonNegativeInt
Expand Down
2 changes: 1 addition & 1 deletion app/model/schema/dex_order_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class AgreementSet(BaseModel, Generic[TokenModel]):
sort_id: int


class CompleteAgreementSet(AgreementSet, Generic[TokenModel]):
class CompleteAgreementSet(AgreementSet[TokenModel], Generic[TokenModel]):
settlement_timestamp: str = Field(description="settlement timestamp")


Expand Down
4 changes: 2 additions & 2 deletions app/model/schema/eth.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ class SendRawTransactionStatus(IntEnum):

class JsonRPCRequest(BaseModel):
method: str = Field(description="method: eth_xxx")
params: list = Field(description="parameters")
params: list[object] = Field(description="parameters")

@field_validator("method")
@classmethod
def method_is_available(cls, v):
def method_is_available(cls, v: str) -> str:
if v[: v.index("_")] not in ["eth"]:
raise ValueError(f"The method {v} is not available")
return v
Expand Down
15 changes: 7 additions & 8 deletions app/model/schema/messaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,29 +68,28 @@ class SendMailRequest(BaseModel):

@field_validator("to_emails")
@classmethod
def is_valid_to_emails(cls, v):
def is_valid_to_emails(cls, v: list[EmailStr]) -> list[EmailStr]:
if len(v) != len(set(v)):
raise ValueError("Each to_emails should be unique value")
return v

@field_validator("file_name")
@classmethod
def is_valid_file_name(cls, v):
def is_valid_file_name(cls, v: str | None) -> str | None:
if v:
match = RE_INVALID_WIN_FILENAME.search(v)
if match:
raise ValueError("File name has invalid character.")
return v

@model_validator(mode="after")
@classmethod
def validate_file(cls, values: Self):
if (values.file_content and not values.file_name) or (
not values.file_content and values.file_name
def validate_file(self) -> Self:
if (self.file_content and not self.file_name) or (
not self.file_content and self.file_name
):
raise ValueError("File content should be posted with name.")
return values
return self


class SendChatWebhookRequest(BaseModel):
message: Json = Field(..., description="Message body")
message: Json[object] = Field(..., description="Message body")
Loading