xync-db 0.4.0__tar.gz → 0.4.2.dev12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/PKG-INFO +1 -1
  2. xync_db-0.4.2.dev12/src/xync_db/migrations/models/0007_agent_auth_notify.py +41 -0
  3. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/models/__init__.py +12 -10
  4. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/.gitignore +0 -0
  5. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/README.md +0 -0
  6. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/pyproject.toml +0 -0
  7. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/__init__.py +0 -0
  8. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/config.py +0 -0
  9. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/enums.py +0 -0
  10. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/exceptions.py +0 -0
  11. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/graph.py +0 -0
  12. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/i18n.py +0 -0
  13. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/logo.png +0 -0
  14. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/CLAUDE.md +0 -0
  15. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/__init__.py +0 -0
  16. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/0001_initial.py +0 -0
  17. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/0002_triggers.py +0 -0
  18. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/0003_files_seed.py +0 -0
  19. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/0004_all_seed.py +0 -0
  20. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/0005_credex_del.py +0 -0
  21. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/0006_credex_orphan.py +0 -0
  22. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/__init__.py +0 -0
  23. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/seed/__init__.py +0 -0
  24. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/seed/a_actor_seed.py +0 -0
  25. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/seed/a_tg_seed.py +0 -0
  26. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/seed/b_htx_seed.py +0 -0
  27. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/migrations/models/seed/xync_files.sql +0 -0
  28. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/models/CLAUDE.md +0 -0
  29. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/py.typed +0 -0
  30. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/shared.py +0 -0
  31. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/typs/__init__.py +0 -0
  32. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/typs/db/__init__.py +0 -0
  33. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/typs/db/actor.py +0 -0
  34. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/typs/db/ad.py +0 -0
  35. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/typs/db/common.py +0 -0
  36. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/typs/db/cred.py +0 -0
  37. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/typs/db/order.py +0 -0
  38. {xync_db-0.4.0 → xync_db-0.4.2.dev12}/src/xync_db/typs/db/pm.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-db
3
- Version: 0.4.0
3
+ Version: 0.4.2.dev12
4
4
  Summary: Xync DB schema: Tortoise ORM models, enums, pydantic DTOs.
5
5
  Author-email: Mike Artemiev <mixartemev@gmail.com>
6
6
  License: LicenseRef-EULA
@@ -0,0 +1,41 @@
1
+ """Agent `auth` change → `agents_upd_auth` channel (reactive session reload).
2
+
3
+ The chrome-extension re-posts an agent's web session (cookies/headers) through `POST /public/set-agent`
4
+ whenever the owner clicks it — but it fires even when nothing changed (the partner just re-opens the
5
+ ext). So instead of reacting in the endpoint on every call, we react in the DB on a real change: the
6
+ existing `agent_upd()` AFTER-UPDATE trigger gains a second, independent branch that emits
7
+ `agents_upd_auth` ONLY when `auth` actually changed (`OLD.auth IS DISTINCT FROM NEW.auth`).
8
+
9
+ service-api's pg-listener (`api.handlers.agents.agents_auth_upd`) then patches the cookies/headers into
10
+ the LIVE http-session of the running agent client (`BaseAgentClient.reload_auth`) — so subsequent
11
+ requests use the fresh session without a service restart — and notifies the agent's owner + the admin.
12
+
13
+ Independent of the `agents_upd_status` branch (status and auth can change together or apart). Payload is
14
+ the full `row_to_json(NEW)` (handler hydrates `Agent(**data)` for actor_id + auth), mirroring
15
+ `actor_person_needs_def_user`.
16
+ """
17
+
18
+ from typing import ClassVar
19
+
20
+ from tortoise.migrations.migration import Migration as BaseMigration
21
+ from tortoise.migrations.operations import RunSQL
22
+
23
+ AGENT_AUTH_SQL = """
24
+ CREATE OR REPLACE FUNCTION agent_upd() returns trigger as $agent_upd_trg$
25
+ BEGIN
26
+ IF OLD.status != NEW.status THEN
27
+ PERFORM pg_notify('agents_upd_status', jsonb_build_array(row_to_json(NEW), OLD.status)::varchar);
28
+ END IF;
29
+ IF OLD.auth IS DISTINCT FROM NEW.auth THEN
30
+ PERFORM pg_notify('agents_upd_auth', row_to_json(NEW)::varchar);
31
+ END IF;
32
+ RETURN NULL;
33
+ END
34
+ $agent_upd_trg$ LANGUAGE plpgsql;
35
+ CREATE OR REPLACE TRIGGER agent_upd AFTER UPDATE ON "agent" FOR EACH ROW EXECUTE FUNCTION agent_upd();
36
+ """
37
+
38
+
39
+ class Migration(BaseMigration):
40
+ dependencies: ClassVar = [("models", "0006_credex_orphan")]
41
+ operations: ClassVar = [RunSQL(AGENT_AUTH_SQL)]
@@ -15,6 +15,7 @@ from cryptography.exceptions import InvalidSignature
15
15
  from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
16
16
  from tortoise import BackwardFKRelation, BackwardOneToOneRelation, BaseDBAsyncClient, connections
17
17
  from tortoise import Model as BaseModel
18
+ from tortoise.expressions import Q
18
19
  from tortoise.fields import (
19
20
  CASCADE,
20
21
  BigIntField,
@@ -685,9 +686,10 @@ class User(TgUser, TsTrait):
685
686
  # тейкеру прячем незашаренные объявы share-hex-бирж (hex IS NULL AND ex∈SHARE_HEX_EX_IDS): без
686
687
  # share-hex url-кнопку не построить. Сужено до этих бирж, чтобы не зацепить hot-биржи без share-hex.
687
688
  # Свои (mine, страница settings) оставляем — их видно для шеринга.
688
- adq = adq.exclude(hex__isnull=True, ad__maker__ex_id__in=SHARE_HEX_EX_IDS)
689
+ # один Q: исключаем строго пересечение (Tortoise's exclude(**kwargs) отрицал бы условия порознь)
690
+ adq = adq.exclude(Q(hex__isnull=True, ad__maker__ex_id__in=SHARE_HEX_EX_IDS))
689
691
  bads = await adq.filter(ad__pair_side__is_sell=False)
690
- # остаток каждой монеты (asset.free) у акторов персон этого юзера, по бирже и монете # noqa: RUF003
692
+ # остаток каждой монеты (asset.free) у акторов персон этого юзера, по бирже и монете # noqa: RUF003
691
693
  coin_balances: dict[int, dict[int, int]] = {}
692
694
  for ex_id, coin_id, total in (
693
695
  await Asset.filter(agent__actor__person__user_id=self.id)
@@ -1016,7 +1018,7 @@ class Agent(Model, TsTrait):
1016
1018
 
1017
1019
  @classmethod
1018
1020
  async def upsert(
1019
- cls, exid: int, host: str, auth: dict, exp: int, rname: str, nick: str, email: str
1021
+ cls, exid: int, host: str, auth: dict, exp: int | None, rname: str, nick: str, email: str = ""
1020
1022
  ) -> tuple[int, Agent, bool]:
1021
1023
  err = 0
1022
1024
  if host and (ex := await Ex.get_or_none(host=host)):
@@ -1317,18 +1319,18 @@ class MyAd(Model): # Road
1317
1319
  )
1318
1320
 
1319
1321
  @classmethod
1320
- async def unshared_hot_ad_ids(cls, hex_ex_ids: list[int] = SHARE_HEX_EX_IDS) -> list[int]:
1321
- """ad_id активных hot-объяв share-hex-бирж без MyAd.hex, чей мейкер-агент ОНЛАЙН (listen-бит,
1322
- `status & 2` → статусы listen|race_listen). Их надо было зашарить (агент слушает), но hex нет —
1323
- для старт-алерта. Объява без hex у НЕактивного агента (off/race, бит 2 снят) — норма (он не шарит),
1324
- не включаем. Гонка (бит 1) для шеринга не нужна, поэтому условие `& 2`, а не `>=3` (hot_mads_query)."""
1322
+ async def unshared_ad_ids(cls, agent_id: int, hex_ex_ids: list[int] = SHARE_HEX_EX_IDS) -> list[int]:
1323
+ """ad_id активных hot-объяв ДАННОГО агента-мейкера на share-hex-бирже без MyAd.hex (не зашарены
1324
+ скрыты от тейкеров get_hot_ads'ом). Для адресного уведомления ВЛАДЕЛЬЦА (не админа), когда его
1325
+ торговля на бирже выключена и он отказался её включать (handlers.agents.share_or_ask).
1326
+ Раньше тут был глобальный старт-алибат `unshared_hot_ad_ids` всем его слал админу бот на старте."""
1325
1327
  return (
1326
1328
  await cls.filter(
1327
1329
  hex__isnull=True,
1328
1330
  ad__status=AdStatus.active,
1329
1331
  ad__maker__ex_id__in=hex_ex_ids,
1332
+ ad__maker__agent__id=agent_id,
1330
1333
  credexs__cred__ovr_pm_id=0,
1331
- ad__maker__agent__status__in=[AgentStatus.listen, AgentStatus.race_listen], # listen-бит (& 2)
1332
1334
  )
1333
1335
  .distinct()
1334
1336
  .values_list("ad_id", flat=True)
@@ -1952,7 +1954,7 @@ class Order(Model, TsTrait):
1952
1954
 
1953
1955
  # партнерские отчисления:
1954
1956
  if self.ad.maker.person.user.status == UserStatus.HOT_PARTNER:
1955
- hspread = abs(self.ad.price - self.ad.pair_side.pair.cur.rate)
1957
+ hspread = abs(self.ad.price - self.ad.pair_side.pair.rate)
1956
1958
  earn = hspread * self.quantity * 0.0001
1957
1959
  fee = int(earn * (0.7 - self.ad.maker.person.user.bonus * 0.0001)) # 1% = 100
1958
1960
  b = await self.ad.maker.person.user.balance(self.ad.pair_side.pair.cur_id)
File without changes
File without changes
File without changes