diff --git a/server/src/uds/REST/methods/transports.py b/server/src/uds/REST/methods/transports.py index 04166a94..36fd36bd 100644 --- a/server/src/uds/REST/methods/transports.py +++ b/server/src/uds/REST/methods/transports.py @@ -64,49 +64,50 @@ class Transports(ModelHandler): return transports.factory().providers().values() def getGui(self, type_: str) -> typing.List[typing.Any]: - try: - field = self.addDefaultFields(transports.actory().lookup(type_).guiDescription(), ['name', 'comments', 'tags', 'priority']) - field = self.addField(field, { - 'name': 'nets_positive', - 'value': True, - 'label': ugettext('Network access'), - 'tooltip': ugettext('If checked, the transport will be enabled for the selected networks. If unchecked, transport will be disabled for selected networks'), - 'type': 'checkbox', - 'order': 100, # At end - }) - field = self.addField(field, { - 'name': 'networks', - 'value': [], - 'values': sorted([{'id': x.id, 'text': x.name} for x in Network.objects.all()], key=lambda x: x['text'].lower()), - 'label': ugettext('Networks'), - 'tooltip': ugettext('Networks associated with this transport. If No network selected, will mean "all networks"'), - 'type': 'multichoice', - 'order': 101 - }) - field = self.addField(field, { - 'name': 'allowed_oss', - 'value': [], - 'values': sorted([{'id': x, 'text': x} for x in OsDetector.knownOss], key=lambda x: x['text'].lower()), - 'label': ugettext('Allowed Devices'), - 'tooltip': ugettext('If empty, any kind of device compatible with this transport will be allowed. Else, only devices compatible with selected values will be allowed'), - 'type': 'multichoice', - 'order': 102 - }) - field = self.addField(field, { - 'name': 'pools', - 'value': [], - 'values': [{'id': x.id, 'text': x.name} for x in ServicePool.objects.all().order_by('name')], - 'label': ugettext('Service Pools'), - 'tooltip': ugettext('Currently assigned services pools'), - 'type': 'multichoice', - 'order': 103 - }) + transport = transports.factory().lookup(type_) - return field - - except Exception: + if not transport: raise self.invalidItemException() + field = self.addDefaultFields(transport.guiDescription(), ['name', 'comments', 'tags', 'priority']) + field = self.addField(field, { + 'name': 'nets_positive', + 'value': True, + 'label': ugettext('Network access'), + 'tooltip': ugettext('If checked, the transport will be enabled for the selected networks. If unchecked, transport will be disabled for selected networks'), + 'type': 'checkbox', + 'order': 100, # At end + }) + field = self.addField(field, { + 'name': 'networks', + 'value': [], + 'values': sorted([{'id': x.id, 'text': x.name} for x in Network.objects.all()], key=lambda x: x['text'].lower()), + 'label': ugettext('Networks'), + 'tooltip': ugettext('Networks associated with this transport. If No network selected, will mean "all networks"'), + 'type': 'multichoice', + 'order': 101 + }) + field = self.addField(field, { + 'name': 'allowed_oss', + 'value': [], + 'values': sorted([{'id': x, 'text': x} for x in OsDetector.knownOss], key=lambda x: x['text'].lower()), + 'label': ugettext('Allowed Devices'), + 'tooltip': ugettext('If empty, any kind of device compatible with this transport will be allowed. Else, only devices compatible with selected values will be allowed'), + 'type': 'multichoice', + 'order': 102 + }) + field = self.addField(field, { + 'name': 'pools', + 'value': [], + 'values': [{'id': x.id, 'text': x.name} for x in ServicePool.objects.all().order_by('name')], + 'label': ugettext('Service Pools'), + 'tooltip': ugettext('Currently assigned services pools'), + 'type': 'multichoice', + 'order': 103 + }) + + return field + def item_as_dict(self, item: Transport) -> typing.Dict[str, typing.Any]: type_ = item.getType() return { diff --git a/server/src/uds/core/transports/__init__.py b/server/src/uds/core/transports/__init__.py index 4c8d4723..3f581d27 100644 --- a/server/src/uds/core/transports/__init__.py +++ b/server/src/uds/core/transports/__init__.py @@ -34,11 +34,12 @@ UDS Service modules interfaces and classes. """ from .transport import Transport from .transport import DIRECT_GROUP, TUNNELED_GROUP +from .transport_factory import TransportsFactory from . import protocols -def factory(): + +def factory() -> TransportsFactory: """ Returns factory for register/access to service providers """ - from .transport_factory import TransportsFactory return TransportsFactory.factory() diff --git a/server/src/uds/services/Sample/__init__.py b/server/src/uds/services/Sample/__init__.py index 5a9bba15..b93d46e4 100644 --- a/server/src/uds/services/Sample/__init__.py +++ b/server/src/uds/services/Sample/__init__.py @@ -40,5 +40,4 @@ For this, we must simply import the class at __init__, UDS will take care of the rest """ -from .SampleProvider import Provider - +from .provider import Provider diff --git a/server/src/uds/services/Sample/SampleUserDeploymentOne.py b/server/src/uds/services/Sample/deployment_one.py similarity index 97% rename from server/src/uds/services/Sample/SampleUserDeploymentOne.py rename to server/src/uds/services/Sample/deployment_one.py index ed557f13..60201049 100644 --- a/server/src/uds/services/Sample/SampleUserDeploymentOne.py +++ b/server/src/uds/services/Sample/deployment_one.py @@ -30,15 +30,22 @@ """ .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com """ - -from uds.core.services import UserDeployment -from uds.core.util.state import State import logging +import typing + +from uds.core import services +from uds.core.util.state import State + +# Not imported at runtime, just for type checking +if typing.TYPE_CHECKING: + from uds import models + from .service import ServiceOne + from .publication import SamplePublication logger = logging.getLogger(__name__) -class SampleUserDeploymentOne(UserDeployment): +class SampleUserDeploymentOne(services.UserDeployment): """ This class generates the user consumable elements of the service tree. @@ -72,17 +79,16 @@ class SampleUserDeploymentOne(UserDeployment): suggestedTime = 5 # Serializable needed methods - def marshal(self): + def marshal(self) -> bytes: """ Does nothing right here, we will use environment storage in this sample """ return b'' - def unmarshal(self, str_): + def unmarshal(self, data: bytes) -> None: """ Does nothing here also, all data are kept at environment storage """ - pass def getName(self): """ diff --git a/server/src/uds/services/Sample/SampleUserDeploymentTwo.py b/server/src/uds/services/Sample/deployment_two.py similarity index 98% rename from server/src/uds/services/Sample/SampleUserDeploymentTwo.py rename to server/src/uds/services/Sample/deployment_two.py index c7044065..2379e554 100644 --- a/server/src/uds/services/Sample/SampleUserDeploymentTwo.py +++ b/server/src/uds/services/Sample/deployment_two.py @@ -30,16 +30,23 @@ """ .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com """ - -from uds.core.services import UserDeployment -from uds.core.util.state import State -import logging import codecs +import logging +import typing + +from uds.core import services +from uds.core.util.state import State + +# Not imported at runtime, just for type checking +if typing.TYPE_CHECKING: + from uds import models + from .service import ServiceOne + from .publication import SamplePublication logger = logging.getLogger(__name__) -class SampleUserDeploymentTwo(UserDeployment): +class SampleUserDeploymentTwo(services.UserDeployment): """ This class generates the user consumable elements of the service tree. diff --git a/server/src/uds/services/Sample/SampleProvider.py b/server/src/uds/services/Sample/provider.py similarity index 87% rename from server/src/uds/services/Sample/SampleProvider.py rename to server/src/uds/services/Sample/provider.py index 434cb16a..2bec3a8e 100644 --- a/server/src/uds/services/Sample/SampleProvider.py +++ b/server/src/uds/services/Sample/provider.py @@ -32,18 +32,24 @@ Created on Jun 22, 2012 .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com """ +import logging +import typing + from django.utils.translation import ugettext_noop as _ -from uds.core.services import ServiceProvider -from .SampleService import ServiceOne, ServiceTwo +from uds.core import services from uds.core.ui import gui +from .service import ServiceOne, ServiceTwo -import logging +# Not imported at runtime, just for type checking +if typing.TYPE_CHECKING: + from uds.core import Module + from uds.core.environment import Environment logger = logging.getLogger(__name__) -class Provider(ServiceProvider): +class Provider(services.ServiceProvider): """ This class represents the sample services provider @@ -87,14 +93,16 @@ class Provider(ServiceProvider): # : Remote host. Here core will translate label and tooltip, remember to # : mark them as _ using ugettext_noop. - remoteHost = gui.TextField(oder=1, + remoteHost = gui.TextField( + oder=1, length=64, label=_('Remote host'), tooltip=_('This fields contains a remote host'), required=True, ) # : Name of your pet (sample, not really needed :-) ) - petName = gui.TextField(order=2, + petName = gui.TextField( + order=2, length=32, label=_('Your pet\'s name'), tooltip=_('If you like, write the name of your pet'), @@ -104,7 +112,8 @@ class Provider(ServiceProvider): # : Age of Methuselah (matusalén in spanish) # : in Spain there is a well-known to say that something is very old, # : "Tiene mas años que matusalén"(is older than Methuselah) - methAge = gui.NumericField(order=3, + methAge = gui.NumericField( + order=3, length=4, # That is, max allowed value is 9999 label=_('Age of Methuselah'), tooltip=_('If you know it, please, tell me!!!'), @@ -113,14 +122,16 @@ class Provider(ServiceProvider): ) # : Is Methuselah istill alive? - methAlive = gui.CheckBoxField(order=4, + methAlive = gui.CheckBoxField( + order=4, label=_('Is Methuselah still alive?'), tooltip=_('If you fail, this will not get saved :-)'), required=True, # : Also means nothing. Check boxes has always a value defvalue=gui.TRUE # : By default, at new item, check this ) - methText = gui.TextField(order=5, + methText = gui.TextField( + order=5, length=512, multiline=5, label=_('Text area'), @@ -130,7 +141,7 @@ class Provider(ServiceProvider): ) # There is more fields type, but not here the best place to cover it - def initialize(self, values=None): + def initialize(self, values: 'Module.ValuesType') -> None: """ We will use the "autosave" feature for form fields, that is more than enought for most providers. (We simply need to store data provided by user @@ -143,8 +154,8 @@ class Provider(ServiceProvider): # If you say meth is alive, you are wrong!!! (i guess..) # values are only passed from administration client. Internals # instantiations are always empty. - if values is not None and self.methAlive.isTrue(): - raise ServiceProvider.ValidationException(_('Methuselah is not alive!!! :-)')) + if values and self.methAlive.isTrue(): + raise services.ServiceProvider.ValidationException(_('Methuselah is not alive!!! :-)')) # Marshal and unmarshal are defaults ones, also enought @@ -152,7 +163,7 @@ class Provider(ServiceProvider): # base class so we don't have to mess with all those things... @staticmethod - def test(env, data): + def test(env: 'Environment', data: typing.Dict[str, str]) -> typing.List[typing.Any]: """ Create your test method here so the admin can push the "check" button and this gets executed. @@ -176,9 +187,8 @@ class Provider(ServiceProvider): try: # We instantiate the provider, but this may fail... instance = Provider(env, data) - logger.debug('Methuselah has {0} years and is {1} :-)' - .format(instance.methAge.value, instance.methAlive.value)) - except ServiceProvider.ValidationException as e: + logger.debug('Methuselah has %s years and is %s :-)', instance.methAge.value, instance.methAlive.value) + except services.ServiceProvider.ValidationException as e: # If we say that meth is alive, instantiation will return [False, str(e)] except Exception as e: @@ -191,15 +201,15 @@ class Provider(ServiceProvider): # # From now onwards, we implement our own methods, that will be used by, # for example, services derived from this provider - def host(self): + def host(self) -> str: """ Sample method, in fact in this we just return the value of host field, that is an string """ return self.remoteHost.value - def methYears(self): + def methYears(self) -> int: """ Another sample return, it will in fact return the Methuselah years """ - return self.methAge.value() + return self.methAge.num() diff --git a/server/src/uds/services/Sample/SamplePublication.py b/server/src/uds/services/Sample/publication.py similarity index 97% rename from server/src/uds/services/Sample/SamplePublication.py rename to server/src/uds/services/Sample/publication.py index 9de1e3ee..a140da97 100644 --- a/server/src/uds/services/Sample/SamplePublication.py +++ b/server/src/uds/services/Sample/publication.py @@ -30,15 +30,19 @@ """ .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com """ +import logging +import typing from django.utils.translation import ugettext as _ from uds.core.services import Publication from uds.core.util.state import State -from datetime import datetime -import logging logger = logging.getLogger(__name__) +# Not imported at runtime, just for type checking +if typing.TYPE_CHECKING: + from .service import ServiceOne, ServiceTwo + class SamplePublication(Publication): """ @@ -79,6 +83,9 @@ class SamplePublication(Publication): """ suggestedTime = 5 # : Suggested recheck time if publication is unfinished in seconds + _name: str = '' + _reason: str = '' + _number: int = -1 def initialize(self): """ @@ -104,9 +111,9 @@ class SamplePublication(Publication): """ deserializes the data and loads it inside instance. """ - logger.debug('Data: {0}'.format(data)) + logger.debug('Data: %s', data) vals = data.decode('utf8').split('\t') - logger.debug('Values: {0}'.format(vals)) + logger.debug('Values: %s', vals) self._name = vals[0] self._reason = vals[1] self._number = int(vals[2]) diff --git a/server/src/uds/services/Sample/SampleService.py b/server/src/uds/services/Sample/service.py similarity index 83% rename from server/src/uds/services/Sample/SampleService.py rename to server/src/uds/services/Sample/service.py index 7154dd9b..9662b0e3 100644 --- a/server/src/uds/services/Sample/SampleService.py +++ b/server/src/uds/services/Sample/service.py @@ -30,20 +30,26 @@ """ .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com """ +import logging +import typing from django.utils.translation import ugettext_noop as _ -from uds.core.services import Service -from .SamplePublication import SamplePublication -from .SampleUserDeploymentOne import SampleUserDeploymentOne -from .SampleUserDeploymentTwo import SampleUserDeploymentTwo - +from uds.core import services from uds.core.ui import gui -import logging +from .publication import SamplePublication +from .deployment_one import SampleUserDeploymentOne +from .deployment_two import SampleUserDeploymentTwo + + +# Not imported at runtime, just for type checking +if typing.TYPE_CHECKING: + from uds.core import Module + from uds.core.environment import Environment logger = logging.getLogger(__name__) -class ServiceOne(Service): +class ServiceOne(services.Service): """ Basic service, the first part (variables) include the description of the service. @@ -114,33 +120,37 @@ class ServiceOne(Service): # If we don't indicate an order, the output order of fields will be # "random" - colour = gui.ChoiceField(order=1, - label=_('Colour'), - tooltip=_('Colour of the field'), - # In this case, the choice can have none value selected by default - required=True, - values=[ gui.choiceItem('red', 'Red'), - gui.choiceItem('green', 'Green'), - gui.choiceItem('blue', 'Blue'), - gui.choiceItem('nonsense', 'Blagenta') - ], - defvalue='1' # Default value is the ID of the choicefield - ) + colour = gui.ChoiceField( + order=1, + label=_('Colour'), + tooltip=_('Colour of the field'), + # In this case, the choice can have none value selected by default + required=True, + values=[ + gui.choiceItem('red', 'Red'), + gui.choiceItem('green', 'Green'), + gui.choiceItem('blue', 'Blue'), + gui.choiceItem('nonsense', 'Blagenta') + ], + defvalue='1' # Default value is the ID of the choicefield + ) - passw = gui.PasswordField(order=2, - label=_('Password'), - tooltip=_('Password for testing purposes'), - required=True, - defvalue='1234' # : Default password are nonsense?? :-) - ) + passw = gui.PasswordField( + order=2, + label=_('Password'), + tooltip=_('Password for testing purposes'), + required=True, + defvalue='1234' # : Default password are nonsense?? :-) + ) - baseName = gui.TextField(order=3, - label=_('Services names'), - tooltip=_('Base name for this user services'), - # In this case, the choice can have none value selected by default - required=True, - defvalue='' # Default value is the ID of the choicefield - ) + baseName = gui.TextField( + order=3, + label=_('Services names'), + tooltip=_('Base name for this user services'), + # In this case, the choice can have none value selected by default + required=True, + defvalue='' # Default value is the ID of the choicefield + ) def initialize(self, values): """ @@ -155,7 +165,7 @@ class ServiceOne(Service): # so we only need to validate params if values is not None if values is not None: if self.colour.value == 'nonsense': - raise Service.ValidationException('The selected colour is invalid!!!') + raise services.Service.ValidationException('The selected colour is invalid!!!') # Services itself are non testeable right now, so we don't even have @@ -189,7 +199,7 @@ class ServiceOne(Service): -class ServiceTwo(Service): +class ServiceTwo(services.Service): """ Just a second service, no comments here (almost same that ServiceOne """