feat(product-suite): add original image batch management

This commit is contained in:
chengma
2026-07-14 15:35:59 +08:00
parent 21d2dd5253
commit e86b9189ab
8 changed files with 759 additions and 37 deletions
+133
View File
@@ -335,6 +335,139 @@ class ImageStudioTests(TempDirMixin, unittest.TestCase):
self.assert_removed(temp_dir)
def test_remove_original_assets_is_atomic_and_reorders_remaining_assets(self):
with self.make_temp_dir() as temp_dir:
db_path = os.path.join(temp_dir, "cmshopee.db")
db.init_db(db_path)
project = image_studio.create_or_get_project(
account_alias="alias",
account_slug="alias_slug",
item_id="51100639510",
path=db_path,
)
local_paths = []
assets = []
for index in range(1, 5):
local_path = os.path.join(temp_dir, "original-%d.png" % index)
with open(local_path, "wb") as fh:
fh.write(b"image-%d" % index)
local_paths.append(local_path)
assets.append(
image_studio.add_asset(
project.id,
image_studio.ASSET_KIND_ORIGINAL,
local_path=local_path,
source_order=index * 10,
path=db_path,
)
)
removed = image_studio.remove_original_assets_if_unused(
project.id,
[assets[0].id, assets[2].id, assets[0].id],
path=db_path,
)
self.assertEqual([assets[0].id, assets[2].id], [asset.id for asset in removed])
remaining = image_studio.list_assets(
project.id,
kind=image_studio.ASSET_KIND_ORIGINAL,
path=db_path,
)
self.assertEqual([assets[1].id, assets[3].id], [asset.id for asset in remaining])
self.assertEqual([1, 2], [asset.source_order for asset in remaining])
self.assertTrue(all(os.path.isfile(path) for path in local_paths))
self.assert_removed(temp_dir)
def test_remove_original_assets_rejects_invalid_or_referenced_batch_without_partial_delete(self):
with self.make_temp_dir() as temp_dir:
db_path = os.path.join(temp_dir, "cmshopee.db")
db.init_db(db_path)
project = image_studio.create_or_get_project(
account_alias="alias",
account_slug="alias_slug",
item_id="51100639510",
path=db_path,
)
other_project = image_studio.create_or_get_project(
account_alias="alias",
account_slug="alias_slug",
item_id="51100639511",
path=db_path,
)
free_asset = image_studio.add_asset(
project.id,
image_studio.ASSET_KIND_ORIGINAL,
source_order=1,
path=db_path,
)
referenced_asset = image_studio.add_asset(
project.id,
image_studio.ASSET_KIND_ORIGINAL,
source_order=2,
path=db_path,
)
selected_asset = image_studio.add_asset(
project.id,
image_studio.ASSET_KIND_ORIGINAL,
source_order=3,
path=db_path,
)
generated_asset = image_studio.add_asset(
project.id,
"generated",
path=db_path,
)
foreign_asset = image_studio.add_asset(
other_project.id,
image_studio.ASSET_KIND_ORIGINAL,
path=db_path,
)
image_studio.create_job(
project.id,
source_asset_id=referenced_asset.id,
path=db_path,
)
image_studio.replace_selections(
project.id,
"main",
[selected_asset.id],
path=db_path,
)
with self.assertRaisesRegex(db.DbError, "引用"):
image_studio.remove_original_assets_if_unused(
project.id,
[free_asset.id, referenced_asset.id],
path=db_path,
)
self.assertIsNotNone(image_studio.get_asset(free_asset.id, path=db_path))
self.assertIsNotNone(image_studio.get_asset(referenced_asset.id, path=db_path))
with self.assertRaisesRegex(db.DbError, "引用"):
image_studio.remove_original_assets_if_unused(
project.id,
[free_asset.id, selected_asset.id],
path=db_path,
)
self.assertIsNotNone(image_studio.get_asset(free_asset.id, path=db_path))
self.assertIsNotNone(image_studio.get_asset(selected_asset.id, path=db_path))
for invalid_id in (generated_asset.id, foreign_asset.id, 999999):
with self.assertRaisesRegex(db.DbError, "不属于当前项目"):
image_studio.remove_original_assets_if_unused(
project.id,
[free_asset.id, invalid_id],
path=db_path,
)
self.assertIsNotNone(image_studio.get_asset(free_asset.id, path=db_path))
with self.assertRaisesRegex(db.DbError, "请选择"):
image_studio.remove_original_assets_if_unused(project.id, [], path=db_path)
self.assert_removed(temp_dir)
def test_sync_original_asset_urls_is_idempotent_and_marks_missing(self):
with self.make_temp_dir() as temp_dir:
db_path = os.path.join(temp_dir, "cmshopee.db")