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
6 changes: 3 additions & 3 deletions backend/api/pos/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,15 +254,15 @@ def validate_category_or_collection(self) -> Self:


class TelegramChatGiftRuleCPO(BaseTelegramChatQuantityRuleCPO):
collection_slug: str | None
collection_id: int | None
model: str | None = None
backdrop: str | None = None
pattern: str | None = None

@model_validator(mode="after")
def validate_category_or_collection(self) -> Self:
if not self.category and not self.collection_slug:
raise ValueError("At least category of collection must be specified")
if not self.category and not self.collection_id:
raise ValueError("At least category or collection must be specified")

return self

Expand Down
3 changes: 2 additions & 1 deletion backend/api/pos/gift.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def from_dto(cls, dto: GiftCollectionsMetadataDTO) -> Self:
class GiftFilterPO(GiftFilterDTO):
@classmethod
def from_query_string(cls, value: str) -> Self:
return cls.model_validate_json(unquote(value))
data = cls.model_validate_json(unquote(value))
return data


class GiftUniqueInfoFDO(BaseFDO):
Expand Down
4 changes: 2 additions & 2 deletions backend/api/routes/admin/chat/rule/gift.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ async def add_chat_gift_rule(
)
new_rule = await action.create(
group_id=rule.group_id,
collection_slug=rule.collection_slug,
collection_id=rule.collection_id,
model=rule.model,
backdrop=rule.backdrop,
pattern=rule.pattern,
Expand All @@ -64,7 +64,7 @@ async def update_chat_gift_rule(
)
updated_rule = await action.update(
rule_id=rule_id,
collection_slug=rule.collection_slug,
collection_id=rule.collection_id,
model=rule.model,
backdrop=rule.backdrop,
pattern=rule.pattern,
Expand Down
6 changes: 3 additions & 3 deletions backend/api/routes/gift.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def get_gifts_owners(


@gift_router.get(
"/{collection_slug}",
"/{collection_id}",
description="Returns an object of gift with their holders (telegram ID and blockchain address)",
responses={
HTTP_200_OK: {"model": GiftUniqueItemsFDO},
Expand All @@ -58,11 +58,11 @@ async def get_gifts_owners(
},
)
async def get_collection_holders(
collection_slug: str,
collection_id: int,
db_session: Session = Depends(get_db_session),
) -> GiftUniqueItemsFDO:
gift_unique_action = GiftUniqueAction(db_session=db_session)
items = gift_unique_action.get_all(collection_slug=collection_slug)
items = gift_unique_action.get_all(collection_id=collection_id)
return GiftUniqueItemsFDO(
items=[GiftUniqueInfoFDO.from_dto(item) for item in items]
)
4 changes: 3 additions & 1 deletion backend/community_manager/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,17 @@ def main() -> None:
health_thread.start()

telethon_service.start_sync()
logger.info("Telegram client catching up...")
telethon_service.client.loop.run_until_complete(telethon_service.client.catch_up())

# Start the Gateway Service as a background task on the same loop
telethon_service.client.loop.create_task(gateway_service.start())
gateway_task = telethon_service.client.loop.create_task(gateway_service.start())

try:
telethon_service.client.run_until_disconnected()
finally:
gateway_service.stop()
telethon_service.client.loop.run_until_complete(gateway_task)


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion backend/core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "core"
version = "1.0.0"
version = "1.0.1"
description = "Access Community Tool – Core package"
authors = [
{ name="danoctua", email="danoctua@gmail.com" }
Expand Down
40 changes: 20 additions & 20 deletions backend/core/src/core/actions/chat/rule/gift.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def check_duplicates(
self,
chat_id: int,
group_id: int,
collection_slug: str | None,
collection_id: int | None,
category: str | None,
entity_id: int | None = None,
) -> None:
Expand All @@ -47,7 +47,7 @@ def check_duplicates(

:param chat_id: The unique identifier for the chat where the rule applies.
:param group_id: The unique identifier for the group where the rule applies.
:param collection_slug: The slug identifying the collection; can be None if not applicable.
:param collection_id: The id identifying the collection; can be None if not applicable.
:param category: The category to which the rule applies; can be None if not applicable.
:param entity_id: Optional identifier for the specific entity to exclude from duplicate checks.

Expand All @@ -56,7 +56,7 @@ def check_duplicates(
existing_rules = self.service.find(
chat_id=chat_id,
group_id=group_id,
collection_slug=collection_slug,
collection_id=collection_id,
category=category,
)
if next(filter(lambda rule: rule.id != entity_id, existing_rules), None):
Expand All @@ -67,41 +67,41 @@ def check_duplicates(

def validate_params(
self,
collection_slug: str | None,
collection_id: int | None,
model: str | None,
backdrop: str | None,
pattern: str | None,
) -> None:
# If the collection slug is not set or attributes are not selected – no need to validate them
if not collection_slug or not any((model, backdrop, pattern)):
# If the collection id is not set or attributes are not selected – no need to validate them
if not collection_id or not any((model, backdrop, pattern)):
return

options = self.gift_unique_service.get_unique_options(
collection_slug=collection_slug
)
# FIXME: Rewrite disabled for now since it needs refactoring
# options = self.gift_unique_service.get_unique_options("...")
options = {}

if model and model not in options.get("models", []):
raise HTTPException(
status_code=HTTP_400_BAD_REQUEST,
detail=f"Model {model!r} is not available for the collection {collection_slug!r}.",
detail=f"Model {model!r} is not available for the collection {collection_id!r}.",
)

if backdrop and backdrop not in options.get("backdrops", []):
raise HTTPException(
status_code=HTTP_400_BAD_REQUEST,
detail=f"Backdrop {backdrop!r} is not available for the collection {collection_slug!r}.",
detail=f"Backdrop {backdrop!r} is not available for the collection {collection_id!r}.",
)

if pattern and pattern not in options.get("patterns", []):
raise HTTPException(
status_code=HTTP_400_BAD_REQUEST,
detail=f"Pattern {pattern!r} is not available for the collection {collection_slug!r}.",
detail=f"Pattern {pattern!r} is not available for the collection {collection_id!r}.",
)

async def create(
self,
group_id: int | None,
collection_slug: str | None,
collection_id: int | None,
model: str | None,
backdrop: str | None,
pattern: str | None,
Expand All @@ -113,16 +113,16 @@ async def create(
self.check_duplicates(
chat_id=self.chat.id,
group_id=group_id,
collection_slug=collection_slug,
collection_id=collection_id,
category=category,
)
self.validate_params(collection_slug, model, backdrop, pattern)
self.validate_params(collection_id, model, backdrop, pattern)

new_rule = self.service.create(
CreateTelegramChatGiftCollectionRuleDTO(
chat_id=self.chat.id,
group_id=group_id,
collection_slug=collection_slug,
collection_id=collection_id,
model=model,
backdrop=backdrop,
pattern=pattern,
Expand All @@ -139,7 +139,7 @@ async def create(
async def update(
self,
rule_id: int,
collection_slug: str | None,
collection_id: int | None,
category: str | None,
model: str | None,
backdrop: str | None,
Expand All @@ -155,16 +155,16 @@ async def update(
self.check_duplicates(
chat_id=self.chat.id,
group_id=rule.group_id,
collection_slug=collection_slug,
collection_id=collection_id,
category=category,
entity_id=rule_id,
)
self.validate_params(collection_slug, model, backdrop, pattern)
self.validate_params(collection_id, model, backdrop, pattern)

updated_rule = self.service.update(
rule=rule,
dto=UpdateTelegramChatGiftCollectionRuleDTO(
collection_slug=collection_slug,
collection_id=collection_id,
category=category,
threshold=threshold,
is_enabled=is_enabled,
Expand Down
14 changes: 7 additions & 7 deletions backend/core/src/core/actions/gift.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ def get_metadata(self) -> GiftCollectionsMetadataDTO:
collections_with_options = []

for collection in all_collections:
options = self.service.get_unique_options(collection_slug=collection.slug)
options = collection.options
collections_with_options.append(
GiftCollectionMetadataDTO(
slug=collection.slug,
id=collection.id,
title=collection.title,
preview_url=collection.preview_url,
supply=collection.supply,
Expand Down Expand Up @@ -89,7 +89,7 @@ def __construct_filter_options_query(
for option in options:
# Basic filtering logic (collection, model, backdrop, pattern)
base_filter = and_(
GiftUnique.collection_slug == option.collection,
GiftUnique.collection_id == option.collection_id,
GiftUnique.telegram_owner_id.isnot(None),
*filter(
None.__ne__,
Expand Down Expand Up @@ -144,18 +144,18 @@ def get_collections_holders(self, options: list[GiftFilterDTO]) -> Sequence[int]
result = self.db_session.execute(query).scalars().all()
return result

def get_all(self, collection_slug: str) -> Sequence[GiftUniqueDTO]:
def get_all(self, collection_id: int) -> Sequence[GiftUniqueDTO]:
"""
Fetches all unique items in a given collection.
"""
try:
self.collection_service.get(slug=collection_slug)
self.collection_service.get(id=collection_id)
except NoResultFound:
raise HTTPException(
status_code=HTTP_404_NOT_FOUND,
detail=f"Collection {collection_slug!r} not found",
detail=f"Collection {collection_id!r} not found",
)
return [
GiftUniqueDTO.from_orm(gift)
for gift in self.service.get_all(collection_slug=collection_slug)
for gift in self.service.get_all(collection_id=collection_id)
]
2 changes: 1 addition & 1 deletion backend/core/src/core/actions/jetton.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async def refresh(self, address_raw: str) -> JettonDTO:
f"refresh_details_{address_raw}", "1", ex=3600, nx=True
):
logger.warning(
f"Refresh details for {address_raw} was triggered already. Please wait for an hour to do it again."
f"Refresh details for {address_raw} was triggered already. Skipping."
)
raise HTTPException(
status_code=HTTP_409_CONFLICT,
Expand Down
11 changes: 5 additions & 6 deletions backend/core/src/core/dtos/chat/rule/gift.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
class BaseTelegramChatGiftCollectionRuleDTO(BaseModel):
threshold: int
is_enabled: bool
collection_slug: str | None
collection_id: int | None
model: str | None
backdrop: str | None
pattern: str | None
category: str | None

@model_validator(mode="after")
def validate_slug_or_category(self) -> Self:
if (self.category is None) == (self.collection_slug is None):
def validate_id_or_category(self) -> Self:
if (self.category is None) == (self.collection_id is None):
raise ValueError(
"Either category or collection_slug must be provided and not both."
"Either category or collection_id must be provided and not both."
)

return self
Expand Down Expand Up @@ -73,9 +73,8 @@ def promote_url(self) -> str | None:
# FIXME: Turn on when market is released
# if self.collection:
# return PROMOTE_GIFT_COLLECTION_TEMPLATE.format(
# collection_slug=self.collection.slug
# collection_id=self.collection.id
# )

return None

@classmethod
Expand Down
28 changes: 15 additions & 13 deletions backend/core/src/core/dtos/gift/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


class GiftCollectionDTO(BaseModel):
slug: str
id: int
title: str
preview_url: str | None
supply: int
Expand All @@ -18,7 +18,7 @@ class GiftCollectionDTO(BaseModel):
@classmethod
def from_orm(cls, obj: GiftCollection) -> Self:
return cls(
slug=obj.slug,
id=obj.id,
title=obj.title,
preview_url=obj.preview_url,
supply=obj.supply,
Expand All @@ -27,9 +27,9 @@ def from_orm(cls, obj: GiftCollection) -> Self:
)

@classmethod
def from_telethon(cls, slug: str, obj: StarGiftUnique, preview_url: str) -> Self:
def from_telethon(cls, id: int, obj: StarGiftUnique, preview_url: str) -> Self:
return cls(
slug=slug,
id=id,
title=obj.title,
preview_url=preview_url,
supply=obj.availability_total,
Expand All @@ -39,7 +39,7 @@ def from_telethon(cls, slug: str, obj: StarGiftUnique, preview_url: str) -> Self


class GiftCollectionMetadataDTO(BaseModel):
slug: str
id: int
title: str
preview_url: str | None
supply: int
Expand All @@ -54,7 +54,7 @@ class GiftCollectionsMetadataDTO(BaseModel):


class GiftFilterDTO(BaseModel):
collection: str
collection_id: int
model: str | None = None
backdrop: str | None = None
pattern: str | None = None
Expand All @@ -68,26 +68,28 @@ class GiftFiltersDTO(BaseModel):
def validate_with_context(
cls, objs: list[GiftFilterDTO], context: GiftCollectionsMetadataDTO
) -> Self:
context_by_slug = {
collection.slug: collection for collection in context.collections
context_by_id = {
collection.id: collection for collection in context.collections
}
for obj in objs:
if not (collection_metadata := context_by_slug.get(obj.collection)):
raise ValueError(f"Collection {obj.collection} not found in metadata")
if not (collection_metadata := context_by_id.get(obj.collection_id)):
raise ValueError(
f"Collection {obj.collection_id} not found in metadata"
)

if obj.model and obj.model not in collection_metadata.models:
raise ValueError(
f"Model {obj.model} not found in collection {obj.collection}"
f"Model {obj.model} not found in collection {obj.collection_id}"
)

if obj.backdrop and obj.backdrop not in collection_metadata.backdrops:
raise ValueError(
f"Backdrop {obj.backdrop} not found in collection {obj.collection}"
f"Backdrop {obj.backdrop} not found in collection {obj.collection_id}"
)

if obj.pattern and obj.pattern not in collection_metadata.patterns:
raise ValueError(
f"Pattern {obj.pattern} not found in collection {obj.collection}"
f"Pattern {obj.pattern} not found in collection {obj.collection_id}"
)

return cls(filters=objs)
Loading