kanban-app/backend/app/services/card_position_service.py

137 lines
No EOL
4.1 KiB
Python

"""Service for managing card positioning and reordering"""
from typing import List, Optional
from app import db
from app.models import Card
class CardPositionService:
"""Service for handling card position management"""
@staticmethod
def reorder_cards_in_list(list_id: int, moved_card_id: int, new_position: float) -> None:
"""
Reorder all cards in a list when one card is moved to a new position.
Args:
list_id: The ID of the list containing the cards
moved_card_id: The ID of the card being moved
new_position: The new position for the moved card
"""
# Get all cards in the list, ordered by their current position
all_cards = (
Card.query.filter_by(list_id=list_id)
.order_by(Card.pos)
.all()
)
# Find the moved card in the list
moved_card = None
other_cards = []
for card in all_cards:
if card.id == moved_card_id:
moved_card = card
else:
other_cards.append(card)
if not moved_card:
return # Card not found in this list
# Remove the moved card from other_cards (already done above)
# Insert the moved card at the new position in other_cards
other_cards.insert(int(new_position), moved_card)
# Update positions for all cards to ensure unique, sequential positions
for index, card in enumerate(other_cards):
card.pos = float(index)
db.session.commit()
@staticmethod
def reorder_cards_between_lists(
from_list_id: int,
to_list_id: int,
moved_card_id: int,
new_position: float
) -> None:
"""
Reorder cards when moving a card from one list to another.
Args:
from_list_id: The source list ID
to_list_id: The destination list ID
moved_card_id: The ID of the card being moved
new_position: The new position in the destination list
"""
# Reorder source list (remove the card and compact positions)
source_cards = (
Card.query.filter_by(list_id=from_list_id)
.filter(Card.id != moved_card_id)
.order_by(Card.pos)
.all()
)
for index, card in enumerate(source_cards):
card.pos = float(index)
# Reorder destination list (insert the card at new position)
dest_cards = (
Card.query.filter_by(list_id=to_list_id)
.order_by(Card.pos)
.all()
)
# Insert moved card at the specified position
dest_cards.insert(int(new_position), None) # Placeholder for moved card
for index, card in enumerate(dest_cards):
if card is None:
# This is where our moved card should go
moved_card = Card.query.get(moved_card_id)
if moved_card:
moved_card.pos = float(index)
else:
card.pos = float(index)
db.session.commit()
@staticmethod
def get_next_position(list_id: int) -> float:
"""
Get the next available position in a list.
Args:
list_id: The ID of the list
Returns:
The next available position (float)
"""
last_card = (
Card.query.filter_by(list_id=list_id)
.order_by(Card.pos.desc())
.first()
)
return float(last_card.pos + 1) if last_card else 0.0
@staticmethod
def ensure_unique_positions(list_id: int) -> None:
"""
Ensure all cards in a list have unique, sequential positions.
Useful for data cleanup.
Args:
list_id: The ID of the list to fix
"""
cards = (
Card.query.filter_by(list_id=list_id)
.order_by(Card.pos)
.all()
)
for index, card in enumerate(cards):
card.pos = float(index)
db.session.commit()