114 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import pickle
 | 
						|
from typing import Optional
 | 
						|
 | 
						|
from sqlalchemy import select, and_
 | 
						|
 | 
						|
from card_attributes.exceptions import CardAttributeException
 | 
						|
from card_attributes.handlers.base_handler import BaseHandler
 | 
						|
from models import CardAttribute, Attribute, Card, Project
 | 
						|
from .card_attributes_query_handler import CardAttributesQueryHandler
 | 
						|
 | 
						|
 | 
						|
class CardAttributesCommandHandler(BaseHandler):
 | 
						|
    async def _create_card_attribute(self, card_id: int, attribute_id: int, value):
 | 
						|
        card_attribute = CardAttribute(
 | 
						|
            card_id=card_id,
 | 
						|
            attribute_id=attribute_id,
 | 
						|
        )
 | 
						|
        card_attribute.set_value(value)
 | 
						|
        self.session.add(card_attribute)
 | 
						|
        await self.session.flush()
 | 
						|
 | 
						|
    async def _set_attribute_after_creation(self, card_id: int, project_attr: Attribute, attributes: Optional[dict] = None):
 | 
						|
        if attributes and project_attr.name in attributes:
 | 
						|
            passed_value = attributes[project_attr.name]
 | 
						|
            return await self._create_card_attribute(card_id, project_attr.id, passed_value)
 | 
						|
 | 
						|
        if project_attr.default_value:
 | 
						|
            default_value = pickle.loads(project_attr.default_value)
 | 
						|
            return await self._create_card_attribute(card_id, project_attr.id, default_value)
 | 
						|
 | 
						|
        if project_attr.is_nullable:
 | 
						|
            return await self._create_card_attribute(card_id, project_attr.id, None)
 | 
						|
 | 
						|
        raise CardAttributeException("Required value was not provided")
 | 
						|
 | 
						|
    async def set_attributes_after_creation(self, card: Card, attributes: Optional[dict] = None):
 | 
						|
        query_handler = CardAttributesQueryHandler(self.session)
 | 
						|
        project_attrs = await query_handler.get_attributes_for_project(card.board_id)
 | 
						|
 | 
						|
        try:
 | 
						|
            for project_attr in project_attrs:
 | 
						|
                await self._set_attribute_after_creation(card.id, project_attr, attributes)
 | 
						|
        except CardAttributeException:
 | 
						|
            raise
 | 
						|
 | 
						|
    async def _set_card_attribute(self, card_id: int, attribute_name: str, value):
 | 
						|
        query_handler = CardAttributesQueryHandler(self.session)
 | 
						|
        attribute = await query_handler.get_attr_by_name(attribute_name)
 | 
						|
        if not attribute:
 | 
						|
            raise CardAttributeException(f"Attribute [{attribute_name}] not found")
 | 
						|
 | 
						|
        stmt = (
 | 
						|
            select(CardAttribute)
 | 
						|
            .where(
 | 
						|
                and_(
 | 
						|
                    CardAttribute.card_id == card_id,
 | 
						|
                    CardAttribute.attribute_id == attribute.id,
 | 
						|
                )
 | 
						|
            )
 | 
						|
        )
 | 
						|
        card_attribute: Optional[CardAttribute] = (await self.session.scalars(stmt)).one_or_none()
 | 
						|
 | 
						|
        if not card_attribute:
 | 
						|
            await self._create_card_attribute(card_id, attribute.id, value)
 | 
						|
        else:
 | 
						|
            card_attribute.set_value(value)
 | 
						|
 | 
						|
    async def set_attr_for_each_card_in_group(self, group_id: int, attribute_name: str, value):
 | 
						|
        query_handler = CardAttributesQueryHandler(self.session)
 | 
						|
        card_ids: list[int] = await query_handler.get_card_ids_by_group_id(group_id)
 | 
						|
 | 
						|
        for card_id in card_ids:
 | 
						|
            await self._set_card_attribute(card_id, attribute_name, value)
 | 
						|
 | 
						|
    async def set_attributes(self, card: Card, attributes: Optional[dict] = None):
 | 
						|
        query_handler = CardAttributesQueryHandler(self.session)
 | 
						|
        project_attrs: list[Attribute] = await query_handler.get_attributes_for_project(card.board_id)
 | 
						|
 | 
						|
        try:
 | 
						|
            for attr_name, attr_value in attributes.items():
 | 
						|
                try:
 | 
						|
                    attr = next(attr for attr in project_attrs if attr.name == attr_name)
 | 
						|
                    if attr.is_applicable_to_group and card.group:
 | 
						|
                        await self.set_attr_for_each_card_in_group(card.group.id, attr_name, attr_value)
 | 
						|
                    else:
 | 
						|
                        await self._set_card_attribute(card.id, attr_name, attr_value)
 | 
						|
                except StopIteration:
 | 
						|
                    pass
 | 
						|
        except CardAttributeException:
 | 
						|
            raise
 | 
						|
 | 
						|
    async def set_project_attributes(self, project: Project, attribute_ids: list[int]):
 | 
						|
        query_handler = CardAttributesQueryHandler(self.session)
 | 
						|
        attributes = await query_handler.get_attributes_by_ids(attribute_ids)
 | 
						|
 | 
						|
        attributes_to_create = []
 | 
						|
        for attribute in attributes:
 | 
						|
            project_attr = await query_handler.get_project_attr(project.id, attribute.id)
 | 
						|
            if not project_attr:
 | 
						|
                attributes_to_create.append(attribute)
 | 
						|
 | 
						|
        async for card in query_handler.get_all_cards_for_project(project.id):
 | 
						|
            await self._add_attributes_to_card(card, attributes_to_create)
 | 
						|
 | 
						|
        project.attributes = attributes
 | 
						|
        await self.session.commit()
 | 
						|
 | 
						|
    async def _add_attributes_to_card(self, card: Card, attributes_to_create: list[Attribute]):
 | 
						|
        card_attribute_ids: set[int] = set((attr.attribute_id for attr in card.attributes))
 | 
						|
 | 
						|
        for attribute in attributes_to_create:
 | 
						|
            if attribute.id not in card_attribute_ids:
 | 
						|
                await self._set_attribute_after_creation(card.id, attribute)
 |