1
0
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:
Adolfo Gómez García 2024-01-26 02:17:05 +01:00
parent d003e48a42
commit 72b02d2560
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
11 changed files with 332 additions and 267 deletions

View File

@ -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)

View File

@ -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,
)

View File

@ -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

View File

@ -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)

View 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,
)
}

View File

@ -33,6 +33,7 @@ Author: Adolfo Gómez, dkmaster at dkmon dot com
# pylint: disable=unused-import
from . import (
auth,
calendar,
connections,
errors,
os,

View 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, ...]

View File

@ -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

View File

@ -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}, '

View File

@ -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>