<commit_before>from ereuse_devicehub.exceptions import StandardError
from ereuse_devicehub.resources.device.component.domain import ComponentDomain
from ereuse_devicehub.resources.device.domain import DeviceDomain
from ereuse_devicehub.resources.domain import Domain
from ereuse_devicehub.resources.place.settings import PlaceSettings
from flask import current_app


class PlaceDomain(Domain):
    resource_settings = PlaceSettings

    @staticmethod
    def get_with_coordinates(coordinates: list) -> dict:
        """
        Gets a place that intersects the given Point coordinates.
        :param coordinates: GEOJSON coordinates that represent a Point
        :return: place
        """
        place = current_app.data.find_one_raw('places', {
            'geo': {
                '$geoIntersects': {
                    '$geometry': {
                        'type': 'Point',
                        'coordinates': coordinates
                    }
                }
            }
        })
        if not place:
            raise NoPlaceForGivenCoordinates()
        return place

    @staticmethod
    def update_devices(original: set, updated: set, replaced_place_id: str or None):
        """
        Given the original set of devices of a place, and the updated version, it updates the database to achieve
        the updated set of devices.

        :param original:
        :param updated:
        :param replaced_place_id: The identifier of the replaced place. If updated is empty, this value is not used.
        :return:
        """
        devices_to_remove_id = original - updated
        children_to_remove_id = ComponentDomain.get_components_in_set(list(devices_to_remove_id))
        devices_to_remove_id |= children_to_remove_id

        devices_to_add_id = updated - original
        children_to_add_id = ComponentDomain.get_components_in_set(list(devices_to_add_id))
        devices_to_add_id |= children_to_add_id

        for device_id in devices_to_remove_id:
            PlaceDomain.device_unset_place(device_id)
        for device_id in devices_to_add_id:
            PlaceDomain.device_set_place(device_id, replaced_place_id)

    @staticmethod
    def device_set_place(device_id: str, place_id: str):
        device = DeviceDomain.get_one(device_id)
        if 'place' in device:
            current_app.data.driver.db['places'].update_one({'_id': device['place']}, {'$pull': {'devices': device_id}})
        current_app.data.driver.db['devices'].update_one({'_id': device_id}, {'$set': {'place': place_id}})

    @staticmethod
    def device_unset_place(device_id: str):
        current_app.data.driver.db['devices'].update_one({'_id': device_id}, {'$unset': {'place': ''}})


class CannotDeleteIfHasEvent(StandardError):
    message = "You cannot delete a place where you performed an event."


class NoPlaceForGivenCoordinates(StandardError):
    """<commit_msg>Fix Server Error when deleting places containing events<commit_after>from ereuse_devicehub.exceptions import StandardError
from ereuse_devicehub.resources.device.component.domain import ComponentDomain
from ereuse_devicehub.resources.device.domain import DeviceDomain
from ereuse_devicehub.resources.domain import Domain
from ereuse_devicehub.resources.place.settings import PlaceSettings
from flask import current_app


class PlaceDomain(Domain):
    resource_settings = PlaceSettings

    @staticmethod
    def get_with_coordinates(coordinates: list) -> dict:
        """
        Gets a place that intersects the given Point coordinates.
        :param coordinates: GEOJSON coordinates that represent a Point
        :return: place
        """
        place = current_app.data.find_one_raw('places', {
            'geo': {
                '$geoIntersects': {
                    '$geometry': {
                        'type': 'Point',
                        'coordinates': coordinates
                    }
                }
            }
        })
        if not place:
            raise NoPlaceForGivenCoordinates()
        return place

    @staticmethod
    def update_devices(original: set, updated: set, replaced_place_id: str or None):
        """
        Given the original set of devices of a place, and the updated version, it updates the database to achieve
        the updated set of devices.

        :param original:
        :param updated:
        :param replaced_place_id: The identifier of the replaced place. If updated is empty, this value is not used.
        :return:
        """
        devices_to_remove_id = original - updated
        children_to_remove_id = ComponentDomain.get_components_in_set(list(devices_to_remove_id))
        devices_to_remove_id |= children_to_remove_id

        devices_to_add_id = updated - original
        children_to_add_id = ComponentDomain.get_components_in_set(list(devices_to_add_id))
        devices_to_add_id |= children_to_add_id

        for device_id in devices_to_remove_id:
            PlaceDomain.device_unset_place(device_id)
        for device_id in devices_to_add_id:
            PlaceDomain.device_set_place(device_id, replaced_place_id)

    @staticmethod
    def device_set_place(device_id: str, place_id: str):
        device = DeviceDomain.get_one(device_id)
        if 'place' in device:
            current_app.data.driver.db['places'].update_one({'_id': device['place']}, {'$pull': {'devices': device_id}})
        current_app.data.driver.db['devices'].update_one({'_id': device_id}, {'$set': {'place': place_id}})

    @staticmethod
    def device_unset_place(device_id: str):
        current_app.data.driver.db['devices'].update_one({'_id': device_id}, {'$unset': {'place': ''}})


class CannotDeleteIfHasEvent(StandardError):
    status_code = 400
    message = 'Delete all the events performed in the place before deleting the place itself.'


class NoPlaceForGivenCoordinates(StandardError):
    """
{'fraction_non_alphanumeric': 0.08652048274689784, 'fraction_numerical': 0.0005099439061703213, 'mean_word_length': 2.9226666666666667, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1999992', 'n_tokens_mistral': 1629, 'n_tokens_neox': 1585, 'n_words': 401}