mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-22 13:34:04 +03:00
refactorized REST for calendar actions
This commit is contained in:
parent
d003e48a42
commit
72b02d2560
@ -119,9 +119,9 @@ async def add_calendar_action(
|
||||
data = {
|
||||
'action': action,
|
||||
'calendar': '',
|
||||
'calendarId': calendar_id,
|
||||
'atStart': at_start,
|
||||
'eventsOffset': events_offset,
|
||||
'calendar_id': calendar_id,
|
||||
'at_start': at_start,
|
||||
'events_offset': events_offset,
|
||||
'params': params or {},
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ async def main():
|
||||
# request_pools() # Not logged in, this will generate an error
|
||||
await login(session, options.auth, options.username, options.password)
|
||||
|
||||
# {"action":"PUBLISH","calendar":"","calendarId":"370b5b59-687e-5a94-8c30-1c9eda6ac005","atStart":true,"eventsOffset":222,"params":{}}
|
||||
# {"action":"PUBLISH","calendar":"","calendar_id":"370b5b59-687e-5a94-8c30-1c9eda6ac005","at_start":true,"events_offset":222,"params":{}}
|
||||
await add_calendar_action(
|
||||
session,
|
||||
service_pool_id=options.service_pool_id,
|
||||
@ -173,7 +173,7 @@ async def main():
|
||||
# action='PUBLISH',
|
||||
# calendar_id='c1221a6d-3848-5fa3-ae98-172662c0f554',
|
||||
# at_start=True,
|
||||
# eventsOffset=222,
|
||||
# events_offset=222,
|
||||
# )
|
||||
|
||||
await logout(session)
|
||||
|
@ -37,11 +37,10 @@ import collections.abc
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from uds.core import types
|
||||
from uds.core import types, consts
|
||||
from uds.core.util import log, ensure
|
||||
from uds.core.util.model import process_uuid
|
||||
from uds.models import Calendar, CalendarAction, CalendarAccess, ServicePool
|
||||
from uds.models.calendar_action import CALENDAR_ACTION_DICT
|
||||
from uds.REST.model import DetailHandler
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
@ -59,7 +58,7 @@ class AccessCalendars(DetailHandler):
|
||||
def as_dict(item: 'CalendarAccess'):
|
||||
return {
|
||||
'id': item.uuid,
|
||||
'calendarId': item.calendar.uuid,
|
||||
'calendar_id': item.calendar.uuid,
|
||||
'calendar': item.calendar.name,
|
||||
'access': item.access,
|
||||
'priority': item.priority,
|
||||
@ -94,7 +93,7 @@ class AccessCalendars(DetailHandler):
|
||||
|
||||
try:
|
||||
calendar: Calendar = Calendar.objects.get(
|
||||
uuid=process_uuid(self._params['calendarId'])
|
||||
uuid=process_uuid(self._params['calendar_id'])
|
||||
)
|
||||
access: str = self._params['access'].upper()
|
||||
if access not in (ALLOW, DENY):
|
||||
@ -144,20 +143,21 @@ class ActionsCalendars(DetailHandler):
|
||||
|
||||
@staticmethod
|
||||
def as_dict(item: 'CalendarAction') -> dict[str, typing.Any]:
|
||||
action = CALENDAR_ACTION_DICT.get(item.action, {})
|
||||
action = consts.calendar.CALENDAR_ACTION_DICT.get(item.action)
|
||||
descrption = action.get('description') if action is not None else ''
|
||||
params = json.loads(item.params)
|
||||
return {
|
||||
'id': item.uuid,
|
||||
'calendarId': item.calendar.uuid,
|
||||
'calendar_id': item.calendar.uuid,
|
||||
'calendar': item.calendar.name,
|
||||
'action': item.action,
|
||||
'actionDescription': action.get('description'),
|
||||
'atStart': item.at_start,
|
||||
'eventsOffset': item.events_offset,
|
||||
'description': descrption,
|
||||
'at_start': item.at_start,
|
||||
'events_offset': item.events_offset,
|
||||
'params': params,
|
||||
'pretty_params': item.prettyParams,
|
||||
'nextExecution': item.next_execution,
|
||||
'lastExecution': item.last_execution,
|
||||
'next_execution': item.next_execution,
|
||||
'last_execution': item.last_execution,
|
||||
}
|
||||
|
||||
def get_items(self, parent: 'Model', item: typing.Optional[str]):
|
||||
@ -178,12 +178,12 @@ class ActionsCalendars(DetailHandler):
|
||||
def get_fields(self, parent: 'Model') -> list[typing.Any]:
|
||||
return [
|
||||
{'calendar': {'title': _('Calendar')}},
|
||||
{'actionDescription': {'title': _('Action')}},
|
||||
{'description': {'title': _('Action')}},
|
||||
{'pretty_params': {'title': _('Parameters')}},
|
||||
{'atStart': {'title': _('Relative to')}},
|
||||
{'eventsOffset': {'title': _('Time offset')}},
|
||||
{'nextExecution': {'title': _('Next execution'), 'type': 'datetime'}},
|
||||
{'lastExecution': {'title': _('Last execution'), 'type': 'datetime'}},
|
||||
{'at_start': {'title': _('Relative to')}},
|
||||
{'events_offset': {'title': _('Time offset')}},
|
||||
{'next_execution': {'title': _('Next execution'), 'type': 'datetime'}},
|
||||
{'last_execution': {'title': _('Last execution'), 'type': 'datetime'}},
|
||||
]
|
||||
|
||||
def save_item(self, parent: 'Model', item: typing.Optional[str]) -> None:
|
||||
@ -191,18 +191,18 @@ class ActionsCalendars(DetailHandler):
|
||||
# If already exists
|
||||
uuid = process_uuid(item) if item is not None else None
|
||||
|
||||
calendar = Calendar.objects.get(uuid=process_uuid(self._params['calendarId']))
|
||||
calendar = Calendar.objects.get(uuid=process_uuid(self._params['calendar_id']))
|
||||
action = self._params['action'].upper()
|
||||
if action not in CALENDAR_ACTION_DICT:
|
||||
if action not in consts.calendar.CALENDAR_ACTION_DICT:
|
||||
raise self.invalid_request_response()
|
||||
eventsOffset = int(self._params['eventsOffset'])
|
||||
atStart = self._params['atStart'] not in ('false', False, '0', 0)
|
||||
events_offset = int(self._params['events_offset'])
|
||||
at_start = self._params['at_start'] not in ('false', False, '0', 0)
|
||||
params = json.dumps(self._params['params'])
|
||||
|
||||
# logger.debug('Got parameters: {} {} {} {} ----> {}'.format(calendar, action, eventsOffset, atStart, params))
|
||||
# logger.debug('Got parameters: {} {} {} {} ----> {}'.format(calendar, action, events_offset, at_start, params))
|
||||
logStr = (
|
||||
f'{"Added" if uuid is None else "Updated"} scheduled action '
|
||||
f'{calendar.name},{action},{eventsOffset},{"start" if atStart else "end"},{params} '
|
||||
f'{calendar.name},{action},{events_offset},{"start" if at_start else "end"},{params} '
|
||||
f'by {self._user.pretty_name}'
|
||||
)
|
||||
|
||||
@ -211,8 +211,8 @@ class ActionsCalendars(DetailHandler):
|
||||
calAction.calendar = calendar # type: ignore
|
||||
calAction.service_pool = parent # type: ignore
|
||||
calAction.action = action
|
||||
calAction.at_start = atStart
|
||||
calAction.events_offset = eventsOffset
|
||||
calAction.at_start = at_start
|
||||
calAction.events_offset = events_offset
|
||||
calAction.params = params
|
||||
calAction.save()
|
||||
else:
|
||||
@ -220,8 +220,8 @@ class ActionsCalendars(DetailHandler):
|
||||
calendar=calendar,
|
||||
service_pool=parent,
|
||||
action=action,
|
||||
at_start=atStart,
|
||||
events_offset=eventsOffset,
|
||||
at_start=at_start,
|
||||
events_offset=events_offset,
|
||||
params=params,
|
||||
)
|
||||
|
||||
|
@ -39,7 +39,7 @@ from django.db.models import Count, Q
|
||||
from django.utils.translation import gettext
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from uds.core import types, exceptions
|
||||
from uds.core import types, exceptions, consts
|
||||
from uds.core.managers.user_service import UserServiceManager
|
||||
from uds.core.ui import gui
|
||||
from uds.core.consts.images import DEFAULT_THUMB_BASE64
|
||||
@ -48,22 +48,6 @@ from uds.core.util.config import GlobalConfig
|
||||
from uds.core.util.model import sql_datetime, process_uuid
|
||||
from uds.core.types.states import State
|
||||
from uds.models import Account, Image, OSManager, Service, ServicePool, ServicePoolGroup, User
|
||||
from uds.models.calendar_action import (
|
||||
CALENDAR_ACTION_ADD_GROUP,
|
||||
CALENDAR_ACTION_ADD_TRANSPORT,
|
||||
CALENDAR_ACTION_CACHE_L1,
|
||||
CALENDAR_ACTION_CACHE_L2,
|
||||
CALENDAR_ACTION_DEL_ALL_GROUPS,
|
||||
CALENDAR_ACTION_DEL_ALL_TRANSPORTS,
|
||||
CALENDAR_ACTION_DEL_GROUP,
|
||||
CALENDAR_ACTION_DEL_TRANSPORT,
|
||||
CALENDAR_ACTION_IGNORE_UNUSED,
|
||||
CALENDAR_ACTION_INITIAL,
|
||||
CALENDAR_ACTION_MAX,
|
||||
CALENDAR_ACTION_PUBLISH,
|
||||
CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES,
|
||||
CALENDAR_ACTION_REMOVE_USERSERVICES,
|
||||
)
|
||||
from uds.REST.model import ModelHandler
|
||||
|
||||
from .op_calendars import AccessCalendars, ActionsCalendars
|
||||
@ -631,35 +615,35 @@ class ServicesPools(ModelHandler):
|
||||
# Returns the action list based on current element, for calendar
|
||||
def actionsList(self, item: 'Model') -> typing.Any:
|
||||
item = ensure.is_instance(item, ServicePool)
|
||||
validActions: tuple[dict, ...] = ()
|
||||
validActions: tuple[types.calendar.CalendarAction, ...] = ()
|
||||
itemInfo = item.service.get_type() # type: ignore
|
||||
if itemInfo.uses_cache is True:
|
||||
validActions += (
|
||||
CALENDAR_ACTION_INITIAL,
|
||||
CALENDAR_ACTION_CACHE_L1,
|
||||
CALENDAR_ACTION_MAX,
|
||||
consts.calendar.CALENDAR_ACTION_INITIAL,
|
||||
consts.calendar.CALENDAR_ACTION_CACHE_L1,
|
||||
consts.calendar.CALENDAR_ACTION_MAX,
|
||||
)
|
||||
if itemInfo.uses_cache_l2 is True:
|
||||
validActions += (CALENDAR_ACTION_CACHE_L2,)
|
||||
validActions += (consts.calendar.CALENDAR_ACTION_CACHE_L2,)
|
||||
|
||||
if itemInfo.publication_type is not None:
|
||||
validActions += (CALENDAR_ACTION_PUBLISH,)
|
||||
validActions += (consts.calendar.CALENDAR_ACTION_PUBLISH,)
|
||||
|
||||
# Transport & groups actions
|
||||
validActions += (
|
||||
CALENDAR_ACTION_ADD_TRANSPORT,
|
||||
CALENDAR_ACTION_DEL_TRANSPORT,
|
||||
CALENDAR_ACTION_DEL_ALL_TRANSPORTS,
|
||||
CALENDAR_ACTION_ADD_GROUP,
|
||||
CALENDAR_ACTION_DEL_GROUP,
|
||||
CALENDAR_ACTION_DEL_ALL_GROUPS,
|
||||
consts.calendar.CALENDAR_ACTION_ADD_TRANSPORT,
|
||||
consts.calendar.CALENDAR_ACTION_DEL_TRANSPORT,
|
||||
consts.calendar.CALENDAR_ACTION_DEL_ALL_TRANSPORTS,
|
||||
consts.calendar.CALENDAR_ACTION_ADD_GROUP,
|
||||
consts.calendar.CALENDAR_ACTION_DEL_GROUP,
|
||||
consts.calendar.CALENDAR_ACTION_DEL_ALL_GROUPS,
|
||||
)
|
||||
|
||||
# Advanced actions
|
||||
validActions += (
|
||||
CALENDAR_ACTION_IGNORE_UNUSED,
|
||||
CALENDAR_ACTION_REMOVE_USERSERVICES,
|
||||
CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES,
|
||||
consts.calendar.CALENDAR_ACTION_IGNORE_UNUSED,
|
||||
consts.calendar.CALENDAR_ACTION_REMOVE_USERSERVICES,
|
||||
consts.calendar.CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES,
|
||||
)
|
||||
return validActions
|
||||
|
||||
|
@ -30,12 +30,12 @@
|
||||
"""
|
||||
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import typing
|
||||
import collections.abc
|
||||
from datetime import datetime
|
||||
import time
|
||||
import typing
|
||||
from datetime import datetime
|
||||
|
||||
from . import actor, auth, images, os, system, cache, tickets, net
|
||||
from . import actor, auth, cache, calendar, images, net, os, system, ticket
|
||||
|
||||
# Date related constants
|
||||
NEVER: typing.Final[datetime] = datetime(1972, 7, 1)
|
||||
|
204
server/src/uds/core/consts/calendar.py
Normal file
204
server/src/uds/core/consts/calendar.py
Normal file
@ -0,0 +1,204 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2024 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core.types.calendar import CalendarAction
|
||||
|
||||
|
||||
# Current posible actions
|
||||
#
|
||||
CALENDAR_ACTION_PUBLISH: typing.Final['CalendarAction'] = {
|
||||
'id': 'PUBLISH',
|
||||
'description': _('Publish'),
|
||||
'params': (),
|
||||
}
|
||||
CALENDAR_ACTION_CACHE_L1: typing.Final['CalendarAction'] = {
|
||||
'id': 'CACHEL1',
|
||||
'description': _('Set cache size'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'size',
|
||||
'description': _('Cache size'),
|
||||
'default': '1',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_CACHE_L2: typing.Final['CalendarAction'] = {
|
||||
'id': 'CACHEL2',
|
||||
'description': _('Set L2 cache size'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'size',
|
||||
'description': _('Cache L2 size'),
|
||||
'default': '1',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_INITIAL: typing.Final['CalendarAction'] = {
|
||||
'id': 'INITIAL',
|
||||
'description': _('Set initial services'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'size',
|
||||
'description': _('Initial services'),
|
||||
'default': '1',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_MAX: typing.Final['CalendarAction'] = {
|
||||
'id': 'MAX',
|
||||
'description': _('Set maximum number of services'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'size',
|
||||
'description': _('Maximum services'),
|
||||
'default': '10',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_ADD_TRANSPORT: typing.Final['CalendarAction'] = {
|
||||
'id': 'ADD_TRANSPORT',
|
||||
'description': _('Add a transport'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'transport',
|
||||
'name': 'transport',
|
||||
'description': _('Transport'),
|
||||
'default': '',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_DEL_TRANSPORT: typing.Final['CalendarAction'] = {
|
||||
'id': 'REMOVE_TRANSPORT',
|
||||
'description': _('Remove a transport'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'transport',
|
||||
'name': 'transport',
|
||||
'description': _('Trasport'),
|
||||
'default': '',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_DEL_ALL_TRANSPORTS: typing.Final['CalendarAction'] = {
|
||||
'id': 'REMOVE_ALL_TRANSPORTS',
|
||||
'description': _('Remove all transports'),
|
||||
'params': (),
|
||||
}
|
||||
CALENDAR_ACTION_ADD_GROUP: typing.Final['CalendarAction'] = {
|
||||
'id': 'ADD_GROUP',
|
||||
'description': _('Add a group'),
|
||||
'params': ({'type': 'group', 'name': 'group', 'description': _('Group'), 'default': ''},),
|
||||
}
|
||||
CALENDAR_ACTION_DEL_GROUP: typing.Final['CalendarAction'] = {
|
||||
'id': 'REMOVE_GROUP',
|
||||
'description': _('Remove a group'),
|
||||
'params': ({'type': 'group', 'name': 'group', 'description': _('Group'), 'default': ''},),
|
||||
}
|
||||
CALENDAR_ACTION_DEL_ALL_GROUPS: typing.Final['CalendarAction'] = {
|
||||
'id': 'REMOVE_ALL_GROUPS',
|
||||
'description': _('Remove all groups'),
|
||||
'params': (),
|
||||
}
|
||||
CALENDAR_ACTION_IGNORE_UNUSED: typing.Final['CalendarAction'] = {
|
||||
'id': 'IGNORE_UNUSED',
|
||||
'description': _('Sets the ignore unused'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'bool',
|
||||
'name': 'state',
|
||||
'description': _('Ignore assigned and unused'),
|
||||
'default': False,
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_REMOVE_USERSERVICES: typing.Final['CalendarAction'] = {
|
||||
'id': 'REMOVE_USERSERVICES',
|
||||
'description': _('Remove ALL assigned user service. USE WITH CAUTION!'),
|
||||
'params': (),
|
||||
}
|
||||
|
||||
CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES: typing.Final['CalendarAction'] = {
|
||||
'id': 'STUCK_USERSERVICES',
|
||||
'description': _('Remove OLD assigned user services.'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'hours',
|
||||
'description': _('Time in hours before considering the user service is OLD.'),
|
||||
'default': '72',
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L1: typing.Final['CalendarAction'] = {
|
||||
'id': 'CLEAN_CACHE_L1',
|
||||
'description': _('Clean L1 cache'),
|
||||
'params': (),
|
||||
}
|
||||
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L2: typing.Final['CalendarAction'] = {
|
||||
'id': 'CLEAN_CACHE_L2',
|
||||
'description': _('Clean L2 cache'),
|
||||
'params': (),
|
||||
}
|
||||
|
||||
|
||||
CALENDAR_ACTION_DICT: typing.Final[dict[str, 'CalendarAction']] = {
|
||||
c['id']: c
|
||||
for c in (
|
||||
CALENDAR_ACTION_PUBLISH,
|
||||
CALENDAR_ACTION_CACHE_L1,
|
||||
CALENDAR_ACTION_CACHE_L2,
|
||||
CALENDAR_ACTION_INITIAL,
|
||||
CALENDAR_ACTION_MAX,
|
||||
CALENDAR_ACTION_ADD_TRANSPORT,
|
||||
CALENDAR_ACTION_DEL_TRANSPORT,
|
||||
CALENDAR_ACTION_DEL_ALL_TRANSPORTS,
|
||||
CALENDAR_ACTION_ADD_GROUP,
|
||||
CALENDAR_ACTION_DEL_GROUP,
|
||||
CALENDAR_ACTION_DEL_ALL_GROUPS,
|
||||
CALENDAR_ACTION_IGNORE_UNUSED,
|
||||
CALENDAR_ACTION_REMOVE_USERSERVICES,
|
||||
CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES,
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L1,
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L2,
|
||||
)
|
||||
}
|
@ -33,6 +33,7 @@ Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
# pylint: disable=unused-import
|
||||
from . import (
|
||||
auth,
|
||||
calendar,
|
||||
connections,
|
||||
errors,
|
||||
os,
|
||||
|
38
server/src/uds/core/types/calendar.py
Normal file
38
server/src/uds/core/types/calendar.py
Normal file
@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2024 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import typing
|
||||
|
||||
class CalendarAction(typing.TypedDict):
|
||||
id: str
|
||||
description: str
|
||||
params: typing.Tuple[typing.Any, ...]
|
@ -44,7 +44,7 @@ from django.db import models
|
||||
from uds.core.util import calendar
|
||||
from uds.core.util import log
|
||||
from uds.core.managers.user_service import UserServiceManager
|
||||
from uds.core import services, types
|
||||
from uds.core import services, types, consts
|
||||
|
||||
from .calendar import Calendar
|
||||
from .uuid_model import UUIDModel
|
||||
@ -58,171 +58,6 @@ from .authenticator import Authenticator
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Current posible actions
|
||||
#
|
||||
CALENDAR_ACTION_PUBLISH: dict[str, typing.Any] = {
|
||||
'id': 'PUBLISH',
|
||||
'description': _('Publish'),
|
||||
'params': (),
|
||||
}
|
||||
CALENDAR_ACTION_CACHE_L1: dict[str, typing.Any] = {
|
||||
'id': 'CACHEL1',
|
||||
'description': _('Set cache size'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'size',
|
||||
'description': _('Cache size'),
|
||||
'default': '1',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_CACHE_L2: dict[str, typing.Any] = {
|
||||
'id': 'CACHEL2',
|
||||
'description': _('Set L2 cache size'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'size',
|
||||
'description': _('Cache L2 size'),
|
||||
'default': '1',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_INITIAL: dict[str, typing.Any] = {
|
||||
'id': 'INITIAL',
|
||||
'description': _('Set initial services'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'size',
|
||||
'description': _('Initial services'),
|
||||
'default': '1',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_MAX: dict[str, typing.Any] = {
|
||||
'id': 'MAX',
|
||||
'description': _('Set maximum number of services'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'size',
|
||||
'description': _('Maximum services'),
|
||||
'default': '10',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_ADD_TRANSPORT: dict[str, typing.Any] = {
|
||||
'id': 'ADD_TRANSPORT',
|
||||
'description': _('Add a transport'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'transport',
|
||||
'name': 'transport',
|
||||
'description': _('Transport'),
|
||||
'default': '',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_DEL_TRANSPORT: dict[str, typing.Any] = {
|
||||
'id': 'REMOVE_TRANSPORT',
|
||||
'description': _('Remove a transport'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'transport',
|
||||
'name': 'transport',
|
||||
'description': _('Trasport'),
|
||||
'default': '',
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_DEL_ALL_TRANSPORTS: dict[str, typing.Any] = {
|
||||
'id': 'REMOVE_ALL_TRANSPORTS',
|
||||
'description': _('Remove all transports'),
|
||||
'params': (),
|
||||
}
|
||||
CALENDAR_ACTION_ADD_GROUP: dict[str, typing.Any] = {
|
||||
'id': 'ADD_GROUP',
|
||||
'description': _('Add a group'),
|
||||
'params': ({'type': 'group', 'name': 'group', 'description': _('Group'), 'default': ''},),
|
||||
}
|
||||
CALENDAR_ACTION_DEL_GROUP: dict[str, typing.Any] = {
|
||||
'id': 'REMOVE_GROUP',
|
||||
'description': _('Remove a group'),
|
||||
'params': ({'type': 'group', 'name': 'group', 'description': _('Group'), 'default': ''},),
|
||||
}
|
||||
CALENDAR_ACTION_DEL_ALL_GROUPS: dict[str, typing.Any] = {
|
||||
'id': 'REMOVE_ALL_GROUPS',
|
||||
'description': _('Remove all groups'),
|
||||
'params': (),
|
||||
}
|
||||
CALENDAR_ACTION_IGNORE_UNUSED: dict[str, typing.Any] = {
|
||||
'id': 'IGNORE_UNUSED',
|
||||
'description': _('Sets the ignore unused'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'bool',
|
||||
'name': 'state',
|
||||
'description': _('Ignore assigned and unused'),
|
||||
'default': False,
|
||||
},
|
||||
),
|
||||
}
|
||||
CALENDAR_ACTION_REMOVE_USERSERVICES: dict[str, typing.Any] = {
|
||||
'id': 'REMOVE_USERSERVICES',
|
||||
'description': _('Remove ALL assigned user service. USE WITH CAUTION!'),
|
||||
'params': (),
|
||||
}
|
||||
|
||||
CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES: dict[str, typing.Any] = {
|
||||
'id': 'STUCK_USERSERVICES',
|
||||
'description': _('Remove OLD assigned user services.'),
|
||||
'params': (
|
||||
{
|
||||
'type': 'numeric',
|
||||
'name': 'hours',
|
||||
'description': _('Time in hours before considering the user service is OLD.'),
|
||||
'default': '72',
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L1: dict[str, typing.Any] = {
|
||||
'id': 'CLEAN_CACHE_L1',
|
||||
'description': _('Clean L1 cache'),
|
||||
'params': (),
|
||||
}
|
||||
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L2: dict[str, typing.Any] = {
|
||||
'id': 'CLEAN_CACHE_L2',
|
||||
'description': _('Clean L2 cache'),
|
||||
'params': (),
|
||||
}
|
||||
|
||||
|
||||
CALENDAR_ACTION_DICT: dict[str, dict] = {
|
||||
c['id']: c
|
||||
for c in (
|
||||
CALENDAR_ACTION_PUBLISH,
|
||||
CALENDAR_ACTION_CACHE_L1,
|
||||
CALENDAR_ACTION_CACHE_L2,
|
||||
CALENDAR_ACTION_INITIAL,
|
||||
CALENDAR_ACTION_MAX,
|
||||
CALENDAR_ACTION_ADD_TRANSPORT,
|
||||
CALENDAR_ACTION_DEL_TRANSPORT,
|
||||
CALENDAR_ACTION_DEL_ALL_TRANSPORTS,
|
||||
CALENDAR_ACTION_ADD_GROUP,
|
||||
CALENDAR_ACTION_DEL_GROUP,
|
||||
CALENDAR_ACTION_DEL_ALL_GROUPS,
|
||||
CALENDAR_ACTION_IGNORE_UNUSED,
|
||||
CALENDAR_ACTION_REMOVE_USERSERVICES,
|
||||
CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES,
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L1,
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L2,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class CalendarAction(UUIDModel):
|
||||
calendar = models.ForeignKey(Calendar, on_delete=models.CASCADE)
|
||||
@ -253,7 +88,7 @@ class CalendarAction(UUIDModel):
|
||||
@property
|
||||
def prettyParams(self) -> str:
|
||||
try:
|
||||
ca = CALENDAR_ACTION_DICT.get(self.action)
|
||||
ca = consts.calendar.CALENDAR_ACTION_DICT.get(self.action)
|
||||
|
||||
if ca is None:
|
||||
raise Exception(f'Action {self.action} not found')
|
||||
@ -333,7 +168,9 @@ class CalendarAction(UUIDModel):
|
||||
|
||||
def remove_userservices() -> None:
|
||||
# 1.- Remove usable assigned services (Ignore "creating ones", just for created)
|
||||
for userService in self.service_pool.assigned_user_services().filter(state=types.states.State.USABLE):
|
||||
for userService in self.service_pool.assigned_user_services().filter(
|
||||
state=types.states.State.USABLE
|
||||
):
|
||||
userService.remove()
|
||||
|
||||
def remove_stuck_userservice() -> None:
|
||||
@ -358,7 +195,7 @@ class CalendarAction(UUIDModel):
|
||||
UserServiceManager().get_cache_state_filter(
|
||||
self.service_pool,
|
||||
services.UserService.L1_CACHE
|
||||
if self.action == CALENDAR_ACTION_CLEAN_CACHE_L1['id']
|
||||
if self.action == consts.calendar.CALENDAR_ACTION_CLEAN_CACHE_L1['id']
|
||||
else services.UserService.L2_CACHE,
|
||||
)
|
||||
):
|
||||
@ -367,7 +204,7 @@ class CalendarAction(UUIDModel):
|
||||
def add_del_transport() -> None:
|
||||
try:
|
||||
t = Transport.objects.get(uuid=params['transport'])
|
||||
if self.action == CALENDAR_ACTION_ADD_TRANSPORT['id']:
|
||||
if self.action == consts.calendar.CALENDAR_ACTION_ADD_TRANSPORT['id']:
|
||||
self.service_pool.transports.add(t)
|
||||
else:
|
||||
self.service_pool.transports.remove(t)
|
||||
@ -380,7 +217,7 @@ class CalendarAction(UUIDModel):
|
||||
try:
|
||||
auth, grp = params['group'].split('@')
|
||||
grp = Authenticator.objects.get(uuid=auth).groups.get(uuid=grp)
|
||||
if self.action == CALENDAR_ACTION_ADD_GROUP['id']:
|
||||
if self.action == consts.calendar.CALENDAR_ACTION_ADD_GROUP['id']:
|
||||
self.service_pool.assignedGroups.add(grp)
|
||||
else:
|
||||
self.service_pool.assignedGroups.remove(grp)
|
||||
@ -389,35 +226,38 @@ class CalendarAction(UUIDModel):
|
||||
|
||||
actions: collections.abc.Mapping[str, tuple[collections.abc.Callable[[], None], bool]] = {
|
||||
# Id, actions (lambda), saveServicePool (bool)
|
||||
CALENDAR_ACTION_CACHE_L1['id']: (set_l1_cache, True),
|
||||
CALENDAR_ACTION_CACHE_L2['id']: (set_l2_cache, True),
|
||||
CALENDAR_ACTION_INITIAL['id']: (set_initial, True),
|
||||
CALENDAR_ACTION_MAX['id']: (set_max, True),
|
||||
CALENDAR_ACTION_PUBLISH['id']: (publish, False),
|
||||
CALENDAR_ACTION_IGNORE_UNUSED['id']: (ignores_unused, True),
|
||||
CALENDAR_ACTION_REMOVE_USERSERVICES['id']: (remove_userservices, False),
|
||||
CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES['id']: (
|
||||
consts.calendar.CALENDAR_ACTION_CACHE_L1['id']: (set_l1_cache, True),
|
||||
consts.calendar.CALENDAR_ACTION_CACHE_L2['id']: (set_l2_cache, True),
|
||||
consts.calendar.CALENDAR_ACTION_INITIAL['id']: (set_initial, True),
|
||||
consts.calendar.CALENDAR_ACTION_MAX['id']: (set_max, True),
|
||||
consts.calendar.CALENDAR_ACTION_PUBLISH['id']: (publish, False),
|
||||
consts.calendar.CALENDAR_ACTION_IGNORE_UNUSED['id']: (ignores_unused, True),
|
||||
consts.calendar.CALENDAR_ACTION_REMOVE_USERSERVICES['id']: (remove_userservices, False),
|
||||
consts.calendar.CALENDAR_ACTION_REMOVE_STUCK_USERSERVICES['id']: (
|
||||
remove_stuck_userservice,
|
||||
False,
|
||||
),
|
||||
CALENDAR_ACTION_DEL_ALL_TRANSPORTS['id']: (del_all_transport, False),
|
||||
CALENDAR_ACTION_DEL_ALL_GROUPS['id']: (del_all_groups, False),
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L1['id']: (clear_cache, False),
|
||||
CALENDAR_ACTION_CLEAN_CACHE_L2['id']: (clear_cache, False),
|
||||
CALENDAR_ACTION_ADD_TRANSPORT['id']: (
|
||||
consts.calendar.CALENDAR_ACTION_DEL_ALL_TRANSPORTS['id']: (del_all_transport, False),
|
||||
consts.calendar.CALENDAR_ACTION_DEL_ALL_GROUPS['id']: (del_all_groups, False),
|
||||
consts.calendar.CALENDAR_ACTION_CLEAN_CACHE_L1['id']: (clear_cache, False),
|
||||
consts.calendar.CALENDAR_ACTION_CLEAN_CACHE_L2['id']: (clear_cache, False),
|
||||
consts.calendar.CALENDAR_ACTION_ADD_TRANSPORT['id']: (
|
||||
add_del_transport,
|
||||
False,
|
||||
),
|
||||
CALENDAR_ACTION_DEL_TRANSPORT['id']: (
|
||||
consts.calendar.CALENDAR_ACTION_DEL_TRANSPORT['id']: (
|
||||
add_del_transport,
|
||||
False,
|
||||
),
|
||||
CALENDAR_ACTION_ADD_GROUP['id']: (add_del_group, False),
|
||||
CALENDAR_ACTION_DEL_GROUP['id']: (add_del_group, False),
|
||||
consts.calendar.CALENDAR_ACTION_ADD_GROUP['id']: (add_del_group, False),
|
||||
consts.calendar.CALENDAR_ACTION_DEL_GROUP['id']: (add_del_group, False),
|
||||
}
|
||||
|
||||
fncAction, saveServicePool = actions.get(self.action, (None, False))
|
||||
|
||||
action = consts.calendar.CALENDAR_ACTION_DICT.get(self.action)
|
||||
description = self.action if not action else action.get('description', self.action)
|
||||
|
||||
if fncAction:
|
||||
try:
|
||||
fncAction()
|
||||
@ -426,25 +266,23 @@ class CalendarAction(UUIDModel):
|
||||
self.service_pool.save()
|
||||
|
||||
self.service_pool.log(
|
||||
f'Executed action {CALENDAR_ACTION_DICT.get(self.action, {}).get("description", self.action)} [{self.prettyParams}]',
|
||||
f'Executed action {description} [{self.prettyParams}]',
|
||||
level=log.LogLevel.INFO,
|
||||
)
|
||||
except Exception:
|
||||
self.service_pool.log(
|
||||
f'Error executing scheduled action {CALENDAR_ACTION_DICT.get(self.action, {}).get("description", self.action)} [{self.prettyParams}]'
|
||||
)
|
||||
self.service_pool.log(f'Error executing scheduled action {description} [{self.prettyParams}]')
|
||||
logger.exception('Error executing scheduled action')
|
||||
else:
|
||||
self.service_pool.log(f'Scheduled action not executed because is not supported: {self.action}')
|
||||
|
||||
# On save, will regenerate nextExecution
|
||||
# On save, will regenerate next_execution
|
||||
if save:
|
||||
self.save()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
lastExecution = self.last_execution or sql_datetime()
|
||||
last_execution = self.last_execution or sql_datetime()
|
||||
possibleNext = calendar.CalendarChecker(self.calendar).next_event(
|
||||
check_from=lastExecution - self.offset, start_event=self.at_start
|
||||
check_from=last_execution - self.offset, start_event=self.at_start
|
||||
)
|
||||
if possibleNext:
|
||||
self.next_execution = possibleNext + self.offset
|
||||
|
@ -78,12 +78,12 @@ class TicketStore(UUIDModel):
|
||||
def generate_uuid() -> str:
|
||||
"""In fact, generates a random string of TICKET_LENGTH chars, that will be used as uuid for the ticket (but is not an uuid compliant string)
|
||||
"""
|
||||
return CryptoManager().random_string(consts.tickets.TICKET_LENGTH).lower() # Temporary fix lower() for compat with 3.0
|
||||
return CryptoManager().random_string(consts.ticket.TICKET_LENGTH).lower() # Temporary fix lower() for compat with 3.0
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
data: typing.Any,
|
||||
validity: int = consts.tickets.DEFAULT_TICKET_VALIDITY_TIME,
|
||||
validity: int = consts.ticket.DEFAULT_TICKET_VALIDITY_TIME,
|
||||
owner: typing.Optional[str] = None,
|
||||
secure: bool = False,
|
||||
) -> str:
|
||||
@ -104,7 +104,7 @@ class TicketStore(UUIDModel):
|
||||
if not owner:
|
||||
raise ValueError('Tried to use a secure ticket without owner')
|
||||
data = CryptoManager().aes_crypt(data, owner.encode())
|
||||
owner = consts.tickets.TICKET_SECURED_ONWER # So data is REALLY encrypted, because key used to encrypt is sustituted by SECURED on DB
|
||||
owner = consts.ticket.TICKET_SECURED_ONWER # So data is REALLY encrypted, because key used to encrypt is sustituted by SECURED on DB
|
||||
|
||||
return TicketStore.objects.create(
|
||||
uuid=TicketStore.generate_uuid(),
|
||||
@ -130,7 +130,7 @@ class TicketStore(UUIDModel):
|
||||
# So, if this is a secure ticket, we must use the SECURED value
|
||||
# And use the real "owner" as key to encrypt/decrypt
|
||||
key = owner.encode()
|
||||
owner = consts.tickets.TICKET_SECURED_ONWER # Generic "secured" owner for secure tickets
|
||||
owner = consts.ticket.TICKET_SECURED_ONWER # Generic "secured" owner for secure tickets
|
||||
|
||||
t = TicketStore.objects.get(uuid=uuid, owner=owner)
|
||||
validity = datetime.timedelta(seconds=t.validity)
|
||||
@ -289,13 +289,13 @@ class TicketStore(UUIDModel):
|
||||
seconds=v.validity + 600
|
||||
): # Delete only really old tickets. Avoid "revalidate" issues
|
||||
v.delete()
|
||||
cleanSince = now - datetime.timedelta(seconds=consts.tickets.MAX_TICKET_VALIDITY_TIME)
|
||||
cleanSince = now - datetime.timedelta(seconds=consts.ticket.MAX_TICKET_VALIDITY_TIME)
|
||||
# Also remove too long tickets, even if they are not (12 hours is the default)
|
||||
TicketStore.objects.filter(stamp__lt=cleanSince).delete()
|
||||
|
||||
def __str__(self) -> str:
|
||||
# Tickets are generated by us, so we know they are safe
|
||||
data = pickle.loads(self.data) if self.owner != consts.tickets.TICKET_SECURED_ONWER else '{Secure Ticket}' # nosec
|
||||
data = pickle.loads(self.data) if self.owner != consts.ticket.TICKET_SECURED_ONWER else '{Secure Ticket}' # nosec
|
||||
|
||||
return (
|
||||
f'Ticket id: {self.uuid}, Owner: {self.owner}, Stamp: {self.stamp}, '
|
||||
|
@ -102,6 +102,6 @@
|
||||
</svg>
|
||||
</div>
|
||||
</uds-root>
|
||||
<script src="/uds/res/admin/runtime.js?stamp=1706127911" type="module"></script><script src="/uds/res/admin/polyfills.js?stamp=1706127911" type="module"></script><script src="/uds/res/admin/main.js?stamp=1706127911" type="module"></script></body>
|
||||
<script src="/uds/res/admin/runtime.js?stamp=1706231732" type="module"></script><script src="/uds/res/admin/polyfills.js?stamp=1706231732" type="module"></script><script src="/uds/res/admin/main.js?stamp=1706231732" type="module"></script></body>
|
||||
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user