refactor: Simplify tag management by removing linkage type from API and UI
This commit refactors the tag management system by removing the linkage type parameter from various components, including the API and frontend. The changes streamline the process of adding and removing tags, allowing for both single and bulk tags to be handled uniformly. The UI has been updated to reflect these changes, enhancing user experience and simplifying the codebase. Documentation has been updated accordingly.
This commit is contained in:
+3
-3
@@ -70,7 +70,7 @@ def add_tags_to_photos_endpoint(
|
||||
)
|
||||
|
||||
photos_updated, tags_added = add_tags_to_photos(
|
||||
db, request.photo_ids, request.tag_names, request.linkage_type
|
||||
db, request.photo_ids, request.tag_names
|
||||
)
|
||||
|
||||
return PhotoTagsResponse(
|
||||
@@ -122,8 +122,8 @@ def get_photo_tags_endpoint(
|
||||
tags_data = get_photo_tags(db, photo_id)
|
||||
|
||||
items = [
|
||||
PhotoTagItem(tag_id=tag_id, tag_name=tag_name, linkage_type=linkage_type)
|
||||
for tag_id, tag_name, linkage_type in tags_data
|
||||
PhotoTagItem(tag_id=tag_id, tag_name=tag_name)
|
||||
for tag_id, tag_name in tags_data
|
||||
]
|
||||
|
||||
return PhotoTagsListResponse(photo_id=photo_id, tags=items, total=len(items))
|
||||
|
||||
@@ -37,7 +37,6 @@ class PhotoTagsRequest(BaseModel):
|
||||
|
||||
photo_ids: List[int] = Field(..., description="Photo IDs")
|
||||
tag_names: List[str] = Field(..., description="Tag names to add/remove")
|
||||
linkage_type: int = Field(0, ge=0, le=1, description="Linkage type: 0=single, 1=bulk")
|
||||
|
||||
|
||||
class PhotoTagsResponse(BaseModel):
|
||||
@@ -66,7 +65,6 @@ class PhotoTagItem(BaseModel):
|
||||
|
||||
tag_id: int
|
||||
tag_name: str
|
||||
linkage_type: int # 0=single, 1=bulk
|
||||
|
||||
|
||||
class PhotoTagsListResponse(BaseModel):
|
||||
|
||||
@@ -18,28 +18,41 @@ def search_photos_by_name(
|
||||
page: int = 1,
|
||||
page_size: int = 50,
|
||||
) -> Tuple[List[Tuple[Photo, str]], int]:
|
||||
"""Search photos by person name (partial, case-insensitive).
|
||||
"""Search photos by person name(s) (partial, case-insensitive).
|
||||
|
||||
Supports multiple names separated by commas (OR logic - photos matching any name).
|
||||
|
||||
Matches desktop behavior exactly:
|
||||
- Searches first_name, last_name, middle_name, maiden_name
|
||||
- Returns (photo, full_name) tuples
|
||||
- Filters by folder_path if provided
|
||||
- Multiple names: comma-separated, searches for photos with ANY matching person
|
||||
"""
|
||||
search_name = (person_name or "").strip().lower()
|
||||
search_name = (person_name or "").strip()
|
||||
if not search_name:
|
||||
return [], 0
|
||||
|
||||
# Find matching people
|
||||
matching_people = (
|
||||
db.query(Person)
|
||||
.filter(
|
||||
# Split by comma and clean up names
|
||||
search_names = [name.strip().lower() for name in search_name.split(',') if name.strip()]
|
||||
if not search_names:
|
||||
return [], 0
|
||||
|
||||
# Build OR conditions for each search name
|
||||
name_conditions = []
|
||||
for search_name_lower in search_names:
|
||||
name_conditions.append(
|
||||
or_(
|
||||
func.lower(Person.first_name).contains(search_name),
|
||||
func.lower(Person.last_name).contains(search_name),
|
||||
func.lower(Person.middle_name).contains(search_name),
|
||||
func.lower(Person.maiden_name).contains(search_name),
|
||||
func.lower(Person.first_name).contains(search_name_lower),
|
||||
func.lower(Person.last_name).contains(search_name_lower),
|
||||
func.lower(Person.middle_name).contains(search_name_lower),
|
||||
func.lower(Person.maiden_name).contains(search_name_lower),
|
||||
)
|
||||
)
|
||||
|
||||
# Find matching people (any of the search names)
|
||||
matching_people = (
|
||||
db.query(Person)
|
||||
.filter(or_(*name_conditions))
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
@@ -34,14 +34,9 @@ def get_or_create_tag(db: Session, tag_name: str) -> Tag:
|
||||
|
||||
|
||||
def add_tags_to_photos(
|
||||
db: Session, photo_ids: List[int], tag_names: List[str], linkage_type: int = 0
|
||||
db: Session, photo_ids: List[int], tag_names: List[str]
|
||||
) -> tuple[int, int]:
|
||||
"""Add tags to photos, matching desktop logic exactly.
|
||||
|
||||
Desktop logic:
|
||||
- linkage_type: 0 = single (manually added to individual photo)
|
||||
- linkage_type: 1 = bulk (applied to all photos in folder)
|
||||
- Uses INSERT ... ON CONFLICT DO UPDATE to update linkage_type if exists
|
||||
"""Add tags to photos.
|
||||
|
||||
Returns:
|
||||
Tuple of (photos_updated, tags_added)
|
||||
@@ -67,7 +62,7 @@ def add_tags_to_photos(
|
||||
tag = get_or_create_tag(db, tag_name)
|
||||
tag_objs.append(tag)
|
||||
|
||||
# Add tags to photos (matching desktop link_photo_tag with linkage_type)
|
||||
# Add tags to photos
|
||||
for photo_id in photo_ids:
|
||||
photo = db.query(Photo).filter(Photo.id == photo_id).first()
|
||||
if not photo:
|
||||
@@ -84,17 +79,13 @@ def add_tags_to_photos(
|
||||
.first()
|
||||
)
|
||||
if existing:
|
||||
# Update linkage_type if different (matching desktop ON CONFLICT DO UPDATE)
|
||||
if existing.linkage_type != linkage_type:
|
||||
existing.linkage_type = linkage_type
|
||||
existing.created_date = datetime.utcnow()
|
||||
tags_added += 1
|
||||
# Linkage already exists, skip
|
||||
continue
|
||||
else:
|
||||
# Create new linkage with linkage_type
|
||||
# Create new linkage
|
||||
linkage = PhotoTagLinkage(
|
||||
photo_id=photo_id,
|
||||
tag_id=tag.id,
|
||||
linkage_type=linkage_type,
|
||||
)
|
||||
db.add(linkage)
|
||||
tags_added += 1
|
||||
@@ -151,11 +142,11 @@ def remove_tags_from_photos(
|
||||
return photos_updated, tags_removed
|
||||
|
||||
|
||||
def get_photo_tags(db: Session, photo_id: int) -> List[tuple[int, str, int]]:
|
||||
"""Get all tags for a photo, matching desktop logic exactly.
|
||||
def get_photo_tags(db: Session, photo_id: int) -> List[tuple[int, str]]:
|
||||
"""Get all tags for a photo.
|
||||
|
||||
Returns:
|
||||
List of (tag_id, tag_name, linkage_type) tuples
|
||||
List of (tag_id, tag_name) tuples
|
||||
"""
|
||||
linkages = (
|
||||
db.query(PhotoTagLinkage, Tag)
|
||||
@@ -166,7 +157,7 @@ def get_photo_tags(db: Session, photo_id: int) -> List[tuple[int, str, int]]:
|
||||
)
|
||||
|
||||
return [
|
||||
(linkage.tag_id, tag.tag_name, linkage.linkage_type)
|
||||
(linkage.tag_id, tag.tag_name)
|
||||
for linkage, tag in linkages
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user