fix: disabling last store/group no longer resets all to enabled
Added store_filters_seeded / group_filters_seeded flags to SyncConfig. _enabled_*_ids now returns None (all enabled) only before first toggle, not when the filter table is empty due to all being disabled. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
"""Add store_filters_seeded and group_filters_seeded to sync_configs."""
|
||||||
|
revision = "0011"
|
||||||
|
down_revision = "0010"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column("sync_configs", sa.Column("store_filters_seeded", sa.Boolean(), nullable=False, server_default="0"))
|
||||||
|
op.add_column("sync_configs", sa.Column("group_filters_seeded", sa.Boolean(), nullable=False, server_default="0"))
|
||||||
|
|
||||||
|
# Mark existing rows as seeded if they already have filters
|
||||||
|
op.execute("""
|
||||||
|
UPDATE sync_configs sc
|
||||||
|
SET store_filters_seeded = 1
|
||||||
|
WHERE EXISTS (
|
||||||
|
SELECT 1 FROM sync_filters sf
|
||||||
|
WHERE sf.sync_config_id = sc.id AND sf.entity_type = 'store'
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
op.execute("""
|
||||||
|
UPDATE sync_configs sc
|
||||||
|
SET group_filters_seeded = 1
|
||||||
|
WHERE EXISTS (
|
||||||
|
SELECT 1 FROM sync_filters sf
|
||||||
|
WHERE sf.sync_config_id = sc.id AND sf.entity_type = 'group'
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column("sync_configs", "group_filters_seeded")
|
||||||
|
op.drop_column("sync_configs", "store_filters_seeded")
|
||||||
@@ -59,6 +59,8 @@ class SyncConfig(Base):
|
|||||||
is_enabled = Column(Boolean, nullable=False, default=False)
|
is_enabled = Column(Boolean, nullable=False, default=False)
|
||||||
evo_mirror_enabled = Column(Boolean, nullable=False, default=False)
|
evo_mirror_enabled = Column(Boolean, nullable=False, default=False)
|
||||||
vk_mirror_enabled = Column(Boolean, nullable=False, default=False)
|
vk_mirror_enabled = Column(Boolean, nullable=False, default=False)
|
||||||
|
store_filters_seeded = Column(Boolean, nullable=False, default=False)
|
||||||
|
group_filters_seeded = Column(Boolean, nullable=False, default=False)
|
||||||
confirmed_at = Column(DateTime, nullable=True)
|
confirmed_at = Column(DateTime, nullable=True)
|
||||||
price_multiplier = Column(Numeric(10, 4), nullable=False, default=1.0)
|
price_multiplier = Column(Numeric(10, 4), nullable=False, default=1.0)
|
||||||
created_at = Column(DateTime, nullable=False, server_default=func.now())
|
created_at = Column(DateTime, nullable=False, server_default=func.now())
|
||||||
|
|||||||
@@ -24,29 +24,25 @@ def _get_or_create_sync_config(db: Session, user_id: int) -> SyncConfig:
|
|||||||
|
|
||||||
|
|
||||||
def _enabled_store_ids(db: Session, user_id: int) -> set[str] | None:
|
def _enabled_store_ids(db: Session, user_id: int) -> set[str] | None:
|
||||||
"""Return set of enabled store evotor_ids, or None if no filters set (all enabled)."""
|
"""Return set of enabled store evotor_ids, or None if filters not yet seeded (all enabled)."""
|
||||||
cfg = db.query(SyncConfig).filter_by(user_id=user_id).first()
|
cfg = db.query(SyncConfig).filter_by(user_id=user_id).first()
|
||||||
if not cfg:
|
if not cfg or not cfg.store_filters_seeded:
|
||||||
return None
|
return None
|
||||||
filters = db.query(SyncFilter).filter_by(
|
filters = db.query(SyncFilter).filter_by(
|
||||||
sync_config_id=cfg.id, entity_type="store", filter_mode="include"
|
sync_config_id=cfg.id, entity_type="store", filter_mode="include"
|
||||||
).all()
|
).all()
|
||||||
if not filters:
|
|
||||||
return None
|
|
||||||
return {f.entity_id for f in filters}
|
return {f.entity_id for f in filters}
|
||||||
|
|
||||||
|
|
||||||
def _enabled_group_ids(db: Session, user_id: int, store_evotor_id: str) -> set[str] | None:
|
def _enabled_group_ids(db: Session, user_id: int, store_evotor_id: str) -> set[str] | None:
|
||||||
"""Return set of enabled group evotor_ids for a store, or None if all enabled."""
|
"""Return set of enabled group evotor_ids for a store, or None if filters not yet seeded (all enabled)."""
|
||||||
cfg = db.query(SyncConfig).filter_by(user_id=user_id).first()
|
cfg = db.query(SyncConfig).filter_by(user_id=user_id).first()
|
||||||
if not cfg:
|
if not cfg or not cfg.group_filters_seeded:
|
||||||
return None
|
return None
|
||||||
filters = db.query(SyncFilter).filter_by(
|
filters = db.query(SyncFilter).filter_by(
|
||||||
sync_config_id=cfg.id, entity_type="group", filter_mode="include",
|
sync_config_id=cfg.id, entity_type="group", filter_mode="include",
|
||||||
parent_entity_id=store_evotor_id,
|
parent_entity_id=store_evotor_id,
|
||||||
).all()
|
).all()
|
||||||
if not filters:
|
|
||||||
return None
|
|
||||||
return {f.entity_id for f in filters}
|
return {f.entity_id for f in filters}
|
||||||
|
|
||||||
|
|
||||||
@@ -166,37 +162,20 @@ async def catalog_store_toggle(store_evotor_id: str, request: Request, db: Sessi
|
|||||||
|
|
||||||
cfg = _get_or_create_sync_config(db, user.id)
|
cfg = _get_or_create_sync_config(db, user.id)
|
||||||
|
|
||||||
# If no filters exist yet, that means all stores are implicitly enabled.
|
|
||||||
# Toggling one store OFF means we create include-filters for all OTHER stores.
|
|
||||||
existing = db.query(SyncFilter).filter_by(
|
existing = db.query(SyncFilter).filter_by(
|
||||||
sync_config_id=cfg.id, entity_type="store", filter_mode="include"
|
sync_config_id=cfg.id, entity_type="store", filter_mode="include"
|
||||||
).all()
|
).all()
|
||||||
existing_ids = {f.entity_id for f in existing}
|
existing_ids = {f.entity_id for f in existing}
|
||||||
|
|
||||||
if store_evotor_id in existing_ids:
|
if cfg.store_filters_seeded:
|
||||||
# Currently enabled → disable: remove its filter
|
if store_evotor_id in existing_ids:
|
||||||
db.query(SyncFilter).filter_by(
|
# Currently enabled → disable: remove its filter
|
||||||
sync_config_id=cfg.id, entity_type="store",
|
db.query(SyncFilter).filter_by(
|
||||||
entity_id=store_evotor_id, filter_mode="include",
|
sync_config_id=cfg.id, entity_type="store",
|
||||||
).delete()
|
entity_id=store_evotor_id, filter_mode="include",
|
||||||
else:
|
).delete()
|
||||||
if not existing_ids:
|
|
||||||
# First toggle: seed include-filters for all OTHER stores
|
|
||||||
all_stores = db.query(CachedStore).filter_by(user_id=user.id).all()
|
|
||||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
|
||||||
for s in all_stores:
|
|
||||||
if s.evotor_id == store_evotor_id:
|
|
||||||
continue
|
|
||||||
db.add(SyncFilter(
|
|
||||||
sync_config_id=cfg.id,
|
|
||||||
entity_type="store",
|
|
||||||
entity_id=s.evotor_id,
|
|
||||||
entity_name=s.name,
|
|
||||||
filter_mode="include",
|
|
||||||
created_at=now,
|
|
||||||
))
|
|
||||||
else:
|
else:
|
||||||
# Re-enable: add its filter back
|
# Currently disabled → re-enable: add its filter back
|
||||||
db.add(SyncFilter(
|
db.add(SyncFilter(
|
||||||
sync_config_id=cfg.id,
|
sync_config_id=cfg.id,
|
||||||
entity_type="store",
|
entity_type="store",
|
||||||
@@ -204,6 +183,22 @@ async def catalog_store_toggle(store_evotor_id: str, request: Request, db: Sessi
|
|||||||
filter_mode="include",
|
filter_mode="include",
|
||||||
created_at=datetime.now(timezone.utc).replace(tzinfo=None),
|
created_at=datetime.now(timezone.utc).replace(tzinfo=None),
|
||||||
))
|
))
|
||||||
|
else:
|
||||||
|
# First toggle ever: seed include-filters for all OTHER stores, mark seeded
|
||||||
|
all_stores = db.query(CachedStore).filter_by(user_id=user.id).all()
|
||||||
|
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||||
|
for s in all_stores:
|
||||||
|
if s.evotor_id == store_evotor_id:
|
||||||
|
continue
|
||||||
|
db.add(SyncFilter(
|
||||||
|
sync_config_id=cfg.id,
|
||||||
|
entity_type="store",
|
||||||
|
entity_id=s.evotor_id,
|
||||||
|
entity_name=s.name,
|
||||||
|
filter_mode="include",
|
||||||
|
created_at=now,
|
||||||
|
))
|
||||||
|
cfg.store_filters_seeded = True
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
return RedirectResponse("/catalog/stores", 303)
|
return RedirectResponse("/catalog/stores", 303)
|
||||||
@@ -227,30 +222,12 @@ async def catalog_group_toggle(
|
|||||||
).all()
|
).all()
|
||||||
existing_ids = {f.entity_id for f in existing}
|
existing_ids = {f.entity_id for f in existing}
|
||||||
|
|
||||||
if group_evotor_id in existing_ids:
|
if cfg.group_filters_seeded:
|
||||||
db.query(SyncFilter).filter_by(
|
if group_evotor_id in existing_ids:
|
||||||
sync_config_id=cfg.id, entity_type="group",
|
db.query(SyncFilter).filter_by(
|
||||||
entity_id=group_evotor_id, filter_mode="include",
|
sync_config_id=cfg.id, entity_type="group",
|
||||||
).delete()
|
entity_id=group_evotor_id, filter_mode="include",
|
||||||
else:
|
).delete()
|
||||||
if not existing_ids:
|
|
||||||
# First toggle: seed include-filters for all OTHER groups in this store
|
|
||||||
all_groups = db.query(CachedGroup).filter_by(
|
|
||||||
user_id=user.id, store_evotor_id=store_evotor_id,
|
|
||||||
).all()
|
|
||||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
|
||||||
for g in all_groups:
|
|
||||||
if g.evotor_id == group_evotor_id:
|
|
||||||
continue
|
|
||||||
db.add(SyncFilter(
|
|
||||||
sync_config_id=cfg.id,
|
|
||||||
entity_type="group",
|
|
||||||
entity_id=g.evotor_id,
|
|
||||||
entity_name=g.name,
|
|
||||||
filter_mode="include",
|
|
||||||
parent_entity_id=store_evotor_id,
|
|
||||||
created_at=now,
|
|
||||||
))
|
|
||||||
else:
|
else:
|
||||||
db.add(SyncFilter(
|
db.add(SyncFilter(
|
||||||
sync_config_id=cfg.id,
|
sync_config_id=cfg.id,
|
||||||
@@ -260,6 +237,25 @@ async def catalog_group_toggle(
|
|||||||
parent_entity_id=store_evotor_id,
|
parent_entity_id=store_evotor_id,
|
||||||
created_at=datetime.now(timezone.utc).replace(tzinfo=None),
|
created_at=datetime.now(timezone.utc).replace(tzinfo=None),
|
||||||
))
|
))
|
||||||
|
else:
|
||||||
|
# First toggle ever: seed include-filters for all OTHER groups in this store, mark seeded
|
||||||
|
all_groups = db.query(CachedGroup).filter_by(
|
||||||
|
user_id=user.id, store_evotor_id=store_evotor_id,
|
||||||
|
).all()
|
||||||
|
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||||
|
for g in all_groups:
|
||||||
|
if g.evotor_id == group_evotor_id:
|
||||||
|
continue
|
||||||
|
db.add(SyncFilter(
|
||||||
|
sync_config_id=cfg.id,
|
||||||
|
entity_type="group",
|
||||||
|
entity_id=g.evotor_id,
|
||||||
|
entity_name=g.name,
|
||||||
|
filter_mode="include",
|
||||||
|
parent_entity_id=store_evotor_id,
|
||||||
|
created_at=now,
|
||||||
|
))
|
||||||
|
cfg.group_filters_seeded = True
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
return RedirectResponse(f"/catalog/stores/{store_evotor_id}/groups", 303)
|
return RedirectResponse(f"/catalog/stores/{store_evotor_id}/groups", 303)
|
||||||
|
|||||||
Reference in New Issue
Block a user