2019-11-04 14:56:01 +01:00
|
|
|
from collections import defaultdict
|
2018-07-09 23:22:26 +02:00
|
|
|
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
|
2015-01-18 15:53:03 +01:00
|
|
|
|
2017-08-24 12:26:55 +02:00
|
|
|
from django.db.models import Model
|
2018-11-03 23:40:20 +01:00
|
|
|
from mypy_extensions import TypedDict
|
2016-01-10 00:17:00 +01:00
|
|
|
|
2020-10-05 12:07:04 +02:00
|
|
|
from .auth import UserDoesNotExist
|
2021-01-20 09:10:23 +01:00
|
|
|
from .autoupdate_bundle import AutoupdateElement, autoupdate_bundle
|
|
|
|
from .cache import ChangeIdTooLowError, element_cache
|
|
|
|
from .utils import is_iterable, split_element_id
|
2020-05-15 18:24:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
AutoupdateFormat = TypedDict(
|
|
|
|
"AutoupdateFormat",
|
|
|
|
{
|
|
|
|
"changed": Dict[str, List[Dict[str, Any]]],
|
|
|
|
"deleted": Dict[str, List[int]],
|
|
|
|
"from_change_id": int,
|
|
|
|
"to_change_id": int,
|
|
|
|
"all_data": bool,
|
|
|
|
},
|
|
|
|
)
|
2018-11-03 23:40:20 +01:00
|
|
|
|
|
|
|
|
2021-01-20 09:10:23 +01:00
|
|
|
def disable_history() -> None:
|
|
|
|
""""""
|
|
|
|
with autoupdate_bundle() as bundle:
|
|
|
|
bundle.disable_history()
|
2020-05-15 18:24:21 +02:00
|
|
|
|
2016-05-29 08:29:14 +02:00
|
|
|
|
2018-11-04 14:02:30 +01:00
|
|
|
def inform_changed_data(
|
2019-01-06 16:22:33 +01:00
|
|
|
instances: Union[Iterable[Model], Model],
|
2019-01-19 15:49:46 +01:00
|
|
|
information: List[str] = None,
|
2019-01-06 16:22:33 +01:00
|
|
|
user_id: Optional[int] = None,
|
2019-11-05 11:26:43 +01:00
|
|
|
disable_history: bool = False,
|
2019-10-18 14:18:49 +02:00
|
|
|
no_delete_on_restriction: bool = False,
|
2019-01-06 16:22:33 +01:00
|
|
|
) -> None:
|
2016-09-18 16:00:31 +02:00
|
|
|
"""
|
|
|
|
Informs the autoupdate system and the caching system about the creation or
|
2018-07-09 23:22:26 +02:00
|
|
|
update of an element.
|
2016-10-01 15:26:00 +02:00
|
|
|
|
2018-01-20 13:57:25 +01:00
|
|
|
The argument instances can be one instance or an iterable over instances.
|
2018-11-04 14:02:30 +01:00
|
|
|
|
|
|
|
History creation is enabled.
|
2016-09-18 16:00:31 +02:00
|
|
|
"""
|
2019-01-19 15:49:46 +01:00
|
|
|
if information is None:
|
|
|
|
information = []
|
2019-11-05 11:26:43 +01:00
|
|
|
if not is_iterable(instances):
|
2019-01-06 16:22:33 +01:00
|
|
|
instances = (instances,)
|
2017-08-18 07:56:16 +02:00
|
|
|
|
2019-11-04 14:56:01 +01:00
|
|
|
root_instances = set(instance.get_root_rest_element() for instance in instances)
|
2020-05-28 13:53:01 +02:00
|
|
|
|
|
|
|
elements = []
|
|
|
|
for root_instance in root_instances:
|
|
|
|
element = AutoupdateElement(
|
2018-11-03 23:40:20 +01:00
|
|
|
id=root_instance.get_rest_pk(),
|
|
|
|
collection_string=root_instance.get_collection_string(),
|
2019-11-05 11:26:43 +01:00
|
|
|
disable_history=disable_history,
|
2018-11-04 14:02:30 +01:00
|
|
|
information=information,
|
|
|
|
user_id=user_id,
|
2019-10-18 14:18:49 +02:00
|
|
|
no_delete_on_restriction=no_delete_on_restriction,
|
2018-11-04 14:02:30 +01:00
|
|
|
)
|
2020-05-28 13:53:01 +02:00
|
|
|
elements.append(element)
|
2019-11-04 14:56:01 +01:00
|
|
|
inform_elements(elements)
|
2015-01-17 14:01:44 +01:00
|
|
|
|
2016-09-30 20:42:58 +02:00
|
|
|
|
2018-11-04 14:02:30 +01:00
|
|
|
def inform_deleted_data(
|
2019-01-06 16:22:33 +01:00
|
|
|
deleted_elements: Iterable[Tuple[str, int]],
|
2019-01-19 15:49:46 +01:00
|
|
|
information: List[str] = None,
|
2019-01-06 16:22:33 +01:00
|
|
|
user_id: Optional[int] = None,
|
|
|
|
) -> None:
|
2015-01-17 14:01:44 +01:00
|
|
|
"""
|
2016-09-18 16:00:31 +02:00
|
|
|
Informs the autoupdate system and the caching system about the deletion of
|
2018-07-09 23:22:26 +02:00
|
|
|
elements.
|
2018-11-04 14:02:30 +01:00
|
|
|
|
|
|
|
History creation is enabled.
|
2016-10-01 15:26:00 +02:00
|
|
|
"""
|
2019-01-19 15:49:46 +01:00
|
|
|
if information is None:
|
|
|
|
information = []
|
2019-11-04 14:56:01 +01:00
|
|
|
|
|
|
|
elements = [
|
|
|
|
AutoupdateElement(
|
2018-11-04 14:02:30 +01:00
|
|
|
id=deleted_element[1],
|
|
|
|
collection_string=deleted_element[0],
|
|
|
|
full_data=None,
|
|
|
|
information=information,
|
|
|
|
user_id=user_id,
|
|
|
|
)
|
2019-11-04 14:56:01 +01:00
|
|
|
for deleted_element in deleted_elements
|
|
|
|
]
|
|
|
|
inform_elements(elements)
|
2016-02-11 11:29:19 +01:00
|
|
|
|
|
|
|
|
2019-11-04 14:56:01 +01:00
|
|
|
def inform_elements(elements: Iterable[AutoupdateElement]) -> None:
|
2017-03-06 16:34:20 +01:00
|
|
|
"""
|
2018-11-04 14:02:30 +01:00
|
|
|
Informs the autoupdate system about some elements. This is used just to send
|
|
|
|
some data to all users.
|
|
|
|
|
|
|
|
If you want to save history information, user id or disable history you
|
|
|
|
have to put information or flag inside the elements.
|
2017-03-06 16:34:20 +01:00
|
|
|
"""
|
2021-01-20 09:10:23 +01:00
|
|
|
with autoupdate_bundle() as bundle:
|
2019-11-04 14:56:01 +01:00
|
|
|
bundle.add(elements)
|
2017-03-06 16:34:20 +01:00
|
|
|
|
|
|
|
|
2020-05-15 18:24:21 +02:00
|
|
|
async def get_autoupdate_data(
|
2020-06-03 14:11:25 +02:00
|
|
|
from_change_id: int, user_id: int
|
2020-10-05 12:07:04 +02:00
|
|
|
) -> Tuple[int, Optional[AutoupdateFormat]]:
|
|
|
|
try:
|
|
|
|
return await _get_autoupdate_data(from_change_id, user_id)
|
|
|
|
except UserDoesNotExist:
|
|
|
|
return 0, None
|
|
|
|
|
|
|
|
|
|
|
|
async def _get_autoupdate_data(
|
|
|
|
from_change_id: int, user_id: int
|
2020-06-03 14:11:25 +02:00
|
|
|
) -> Tuple[int, Optional[AutoupdateFormat]]:
|
|
|
|
"""
|
|
|
|
Returns the max_change_id and the autoupdate from from_change_id to max_change_id
|
|
|
|
"""
|
2020-05-15 18:24:21 +02:00
|
|
|
try:
|
2020-06-03 14:11:25 +02:00
|
|
|
(
|
|
|
|
max_change_id,
|
|
|
|
changed_elements,
|
|
|
|
deleted_element_ids,
|
|
|
|
) = await element_cache.get_data_since(user_id, from_change_id)
|
2020-05-15 18:24:21 +02:00
|
|
|
except ChangeIdTooLowError:
|
|
|
|
# The change_id is lower the the lowerst change_id in redis. Return all data
|
2020-06-03 14:11:25 +02:00
|
|
|
(
|
|
|
|
max_change_id,
|
|
|
|
changed_elements,
|
|
|
|
) = await element_cache.get_all_data_list_with_max_change_id(user_id)
|
2020-05-15 18:24:21 +02:00
|
|
|
deleted_elements: Dict[str, List[int]] = {}
|
2020-06-03 14:11:25 +02:00
|
|
|
all_data = True
|
2020-05-15 18:24:21 +02:00
|
|
|
else:
|
|
|
|
all_data = False
|
|
|
|
deleted_elements = defaultdict(list)
|
|
|
|
for element_id in deleted_element_ids:
|
|
|
|
collection_string, id = split_element_id(element_id)
|
|
|
|
deleted_elements[collection_string].append(id)
|
|
|
|
|
|
|
|
# Check, if the autoupdate has any data.
|
|
|
|
if not changed_elements and not deleted_element_ids:
|
|
|
|
# Skip empty updates
|
2020-06-03 14:11:25 +02:00
|
|
|
return max_change_id, None
|
2020-05-15 18:24:21 +02:00
|
|
|
else:
|
|
|
|
# Normal autoupdate with data
|
2020-06-03 14:11:25 +02:00
|
|
|
return (
|
|
|
|
max_change_id,
|
|
|
|
AutoupdateFormat(
|
|
|
|
changed=changed_elements,
|
|
|
|
deleted=deleted_elements,
|
|
|
|
from_change_id=from_change_id,
|
|
|
|
to_change_id=max_change_id,
|
|
|
|
all_data=all_data,
|
|
|
|
),
|
2020-05-15 18:24:21 +02:00
|
|
|
)
|