Merge branch 'dev' into feature/new-tariffs
This commit is contained in:
@@ -12,6 +12,7 @@ from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
|
||||
from ..models import (
|
||||
User,
|
||||
UserTelegramAvatar,
|
||||
Subscription,
|
||||
Payment,
|
||||
PromoCodeActivation,
|
||||
@@ -112,6 +113,45 @@ async def get_user_by_telegram_id(
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
|
||||
async def get_user_telegram_avatar(
|
||||
session: AsyncSession,
|
||||
user_id: int,
|
||||
) -> Optional[UserTelegramAvatar]:
|
||||
stmt = select(UserTelegramAvatar).where(UserTelegramAvatar.user_id == user_id)
|
||||
result = await session.execute(stmt)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
|
||||
async def upsert_user_telegram_avatar(
|
||||
session: AsyncSession,
|
||||
*,
|
||||
user_id: int,
|
||||
file_unique_id: Optional[str],
|
||||
content_type: str,
|
||||
image_bytes: bytes,
|
||||
) -> UserTelegramAvatar:
|
||||
avatar = await get_user_telegram_avatar(session, user_id)
|
||||
if avatar is None:
|
||||
avatar = UserTelegramAvatar(
|
||||
user_id=user_id,
|
||||
file_unique_id=file_unique_id,
|
||||
content_type=content_type,
|
||||
image_bytes=image_bytes,
|
||||
size_bytes=len(image_bytes),
|
||||
updated_at=datetime.now(timezone.utc),
|
||||
)
|
||||
session.add(avatar)
|
||||
else:
|
||||
avatar.file_unique_id = file_unique_id
|
||||
avatar.content_type = content_type
|
||||
avatar.image_bytes = image_bytes
|
||||
avatar.size_bytes = len(image_bytes)
|
||||
avatar.updated_at = datetime.now(timezone.utc)
|
||||
await session.flush()
|
||||
await session.refresh(avatar)
|
||||
return avatar
|
||||
|
||||
|
||||
async def get_user_by_panel_uuid(
|
||||
session: AsyncSession, panel_uuid: str
|
||||
) -> Optional[User]:
|
||||
@@ -426,6 +466,22 @@ async def merge_users(
|
||||
.values(user_id=target_user_id)
|
||||
)
|
||||
|
||||
target_has_avatar = (
|
||||
await session.execute(
|
||||
select(UserTelegramAvatar.user_id).where(UserTelegramAvatar.user_id == target_user_id)
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
if target_has_avatar:
|
||||
await session.execute(
|
||||
delete(UserTelegramAvatar).where(UserTelegramAvatar.user_id == source_user_id)
|
||||
)
|
||||
else:
|
||||
await session.execute(
|
||||
update(UserTelegramAvatar)
|
||||
.where(UserTelegramAvatar.user_id == source_user_id)
|
||||
.values(user_id=target_user_id)
|
||||
)
|
||||
|
||||
subscription_update_values: Dict[str, Any] = {"user_id": target_user_id}
|
||||
if panel_uuid_to_keep:
|
||||
subscription_update_values["panel_user_uuid"] = panel_uuid_to_keep
|
||||
@@ -684,6 +740,7 @@ async def delete_user_and_relations(session: AsyncSession, user_id: int) -> bool
|
||||
)
|
||||
await session.execute(delete(UserBilling).where(UserBilling.user_id == user_id))
|
||||
await session.execute(delete(AdAttribution).where(AdAttribution.user_id == user_id))
|
||||
await session.execute(delete(UserTelegramAvatar).where(UserTelegramAvatar.user_id == user_id))
|
||||
|
||||
await session.delete(user)
|
||||
await session.flush()
|
||||
|
||||
+33
-3
@@ -303,7 +303,32 @@ def _migration_0010_add_email_magic_token_hash(connection: Connection) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _migration_0011_add_tariffs_schema(connection: Connection) -> None:
|
||||
def _migration_0011_add_user_telegram_avatars(connection: Connection) -> None:
|
||||
connection.execute(
|
||||
text(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS user_telegram_avatars (
|
||||
user_id BIGINT PRIMARY KEY REFERENCES users(user_id),
|
||||
file_unique_id VARCHAR,
|
||||
content_type VARCHAR(64) NOT NULL DEFAULT 'image/jpeg',
|
||||
image_bytes BYTEA NOT NULL,
|
||||
size_bytes INTEGER NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)
|
||||
"""
|
||||
)
|
||||
)
|
||||
connection.execute(
|
||||
text(
|
||||
"""
|
||||
CREATE INDEX IF NOT EXISTS ix_user_telegram_avatars_file_unique_id
|
||||
ON user_telegram_avatars (file_unique_id)
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _migration_0012_add_tariffs_schema(connection: Connection) -> None:
|
||||
inspector = inspect(connection)
|
||||
|
||||
sub_columns: Set[str] = {col["name"] for col in inspector.get_columns("subscriptions")}
|
||||
@@ -497,9 +522,14 @@ MIGRATIONS: List[Migration] = [
|
||||
upgrade=_migration_0010_add_email_magic_token_hash,
|
||||
),
|
||||
Migration(
|
||||
id="0011_add_tariffs_schema",
|
||||
id="0011_add_user_telegram_avatars",
|
||||
description="Cache compact Telegram profile avatars for WebApp profiles",
|
||||
upgrade=_migration_0011_add_user_telegram_avatars,
|
||||
),
|
||||
Migration(
|
||||
id="0012_add_tariffs_schema",
|
||||
description="Add tariff catalog columns and traffic accounting tables",
|
||||
upgrade=_migration_0011_add_tariffs_schema,
|
||||
upgrade=_migration_0012_add_tariffs_schema,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
+24
-1
@@ -1,4 +1,4 @@
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, Float, ForeignKey, UniqueConstraint, Text, BigInteger, Index, Numeric
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, Float, ForeignKey, UniqueConstraint, Text, BigInteger, Index, Numeric, LargeBinary
|
||||
from sqlalchemy.orm import relationship, DeclarativeBase
|
||||
from sqlalchemy.ext.asyncio import AsyncAttrs
|
||||
from sqlalchemy.sql import func
|
||||
@@ -59,6 +59,29 @@ class User(Base):
|
||||
return f"<User(user_id={self.user_id}, username='{self.username}')>"
|
||||
|
||||
|
||||
class UserTelegramAvatar(Base):
|
||||
__tablename__ = "user_telegram_avatars"
|
||||
|
||||
user_id = Column(
|
||||
BigInteger,
|
||||
ForeignKey("users.user_id"),
|
||||
primary_key=True,
|
||||
index=True,
|
||||
)
|
||||
file_unique_id = Column(String, nullable=True, index=True)
|
||||
content_type = Column(String(64), nullable=False, default="image/jpeg")
|
||||
image_bytes = Column(LargeBinary, nullable=False)
|
||||
size_bytes = Column(Integer, nullable=False)
|
||||
updated_at = Column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
user = relationship("User")
|
||||
|
||||
|
||||
class Subscription(Base):
|
||||
__tablename__ = "subscriptions"
|
||||
__table_args__ = (
|
||||
|
||||
Reference in New Issue
Block a user