1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-25 23:21:41 +03:00

* Adding more type checking (pylance type checking works fin with theese new "checks")

* Removed redundant fields not used
This commit is contained in:
Adolfo Gómez García 2020-11-11 13:31:27 +01:00
parent 8cd5437429
commit 1ab534c3aa
30 changed files with 154 additions and 109 deletions

View File

@ -100,7 +100,7 @@ class StatsManager:
self,
ownerType: int,
counterType: int,
ownerIds: typing.Union[typing.Iterable[int], int],
ownerIds: typing.Union[typing.Iterable[int], int, None],
since: datetime.datetime,
to: datetime.datetime,
interval: typing.Optional[int],

View File

@ -113,8 +113,7 @@ def getCounters(obj: CounterClass, counterType: int, **kwargs) -> typing.Generat
owner_ids = None
for i in statsManager().getCounters(__transDict[type(obj)], counterType, owner_ids, since, to, kwargs.get('interval'), kwargs.get('max_intervals'), limit, use_max):
val = (datetime.datetime.fromtimestamp(i.stamp), i.value)
yield val
yield (datetime.datetime.fromtimestamp(i.stamp), i.value)
def getCounterTitle(counterType: int) -> str:

View File

@ -101,11 +101,11 @@ class StorageAsDict(MutableMapping):
return DBStorage.objects
@property
def _filtered(self) -> models.QuerySet:
def _filtered(self) -> 'models.QuerySet[DBStorage]':
fltr = self._db.filter(owner=self._owner)
if self._group:
fltr = fltr.filter(attr1=self._group)
return fltr
return typing.cast('models.QuerySet[DBStorage]', fltr)
def _key(self, key: str) -> str:
if key[0] == '#':
@ -120,7 +120,7 @@ class StorageAsDict(MutableMapping):
dbk = self._key(key)
logger.debug('Getitem: %s', dbk)
try:
c: DBStorage = self._db.get(pk=dbk)
c: DBStorage = typing.cast(DBStorage, self._db.get(pk=dbk))
return _decodeValue(dbk, c.data)[1] # Ignores original key
except DBStorage.DoesNotExist:
return None

View File

@ -1,4 +1,4 @@
# Generated by Django 3.1.2 on 2020-11-11 11:23
# Generated by Django 3.1.2 on 2020-11-11 13:29
from django.db import migrations
@ -14,6 +14,10 @@ class Migration(migrations.Migration):
model_name='metapool',
name='accessCalendars',
),
migrations.RemoveField(
model_name='metapool',
name='pools',
),
migrations.RemoveField(
model_name='servicepool',
name='accessCalendars',

View File

@ -62,7 +62,7 @@ from .group import Group
# Provisioned services
from .service_pool import ServicePool # New name
from .meta_pool import MetaPool
from .meta_pool import MetaPool, MetaPoolMember
from .service_pool_group import ServicePoolGroup
from .service_pool_publication import ServicePoolPublication
from .user_service import UserService

View File

@ -56,7 +56,7 @@ class Group(UUIDModel):
This class represents a group, associated with one authenticator
"""
# pylint: disable=model-missing-unicode
manager: Authenticator = UnsavedForeignKey(Authenticator, on_delete=models.CASCADE, related_name='groups')
manager: 'models.ForeignKey[Group, Authenticator]' = UnsavedForeignKey(Authenticator, on_delete=models.CASCADE, related_name='groups')
name = models.CharField(max_length=128, db_index=True)
state = models.CharField(max_length=1, default=State.ACTIVE, db_index=True)
comments = models.CharField(max_length=256, default='')

View File

@ -49,11 +49,11 @@ from .image import Image
from .service_pool_group import ServicePoolGroup
from .service_pool import ServicePool
from .group import Group
from .calendar import Calendar
if typing.TYPE_CHECKING:
import datetime
from .user import User
from uds.models import User, CalendarAccessMeta
logger = logging.getLogger(__name__)
@ -87,11 +87,13 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
# Default fallback action for access
fallbackAccess = models.CharField(default=states.action.ALLOW, max_length=8)
pools = models.ManyToManyField(ServicePool, through='MetapoolMember', related_name='meta')
# Pool selection policy
policy = models.SmallIntegerField(default=0)
# "fake" relations declarations for type checking
calendarAccess: 'models.QuerySet[CalendarAccessMeta]'
members: 'models.QuerySet[MetaPoolMember]'
class Meta(UUIDModel.Meta):
"""
Meta class to declare the name of the table at database
@ -106,10 +108,10 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
bool -- [description]
"""
total, maintenance = 0, 0
p: ServicePool
for p in self.pools.all():
p: 'MetaPoolMember'
for p in self.members.all():
total += 1
if p.isInMaintenance():
if p.pool.isInMaintenance():
maintenance += 1
return total == maintenance
@ -137,7 +139,7 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
return self.name
@staticmethod
def getForGroups(groups: typing.Iterable['Group'], user: typing.Optional['User'] = None) -> QuerySet:
def getForGroups(groups: typing.Iterable['Group'], user: typing.Optional['User'] = None) -> 'QuerySet[MetaPool]':
"""
Return deployed services with publications for the groups requested.
@ -157,12 +159,12 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
'servicesPoolGroup__image',
'assignedGroups',
'assignedGroups',
'pools',
'pools__service',
'pools__service__provider',
'pools__image',
'pools__transports',
'pools__transports__networks',
'members__pool',
'members__pool__service',
'members__pool__service__provider',
'members__pool__image',
'members__pool__transports',
'members__pool__transports__networks',
'calendarAccess',
'calendarAccess__calendar',
'calendarAccess__calendar__rules',
@ -171,11 +173,11 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
if user:
meta = meta.annotate(
number_in_use=models.Count(
'pools__userServices',
'members__pool__userServices',
filter=models.Q(
pools__userServices__user=user,
pools__userServices__in_use=True,
pools__userServices__state__in=states.userService.USABLE
members__pool__userServices__user=user,
members__pool__userServices__in_use=True,
members__pool__userServices__state__in=states.userService.USABLE
)
)
)
@ -204,7 +206,7 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
def __str__(self):
return 'Meta pool: {}, no. pools: {}, visible: {}, policy: {}'.format(
self.name, self.pools.all().count(), self.visible, self.policy
self.name, self.members.all().count(), self.visible, self.policy
)
@ -213,8 +215,8 @@ signals.pre_delete.connect(MetaPool.beforeDelete, sender=MetaPool)
class MetaPoolMember(UUIDModel):
pool: ServicePool = models.ForeignKey(ServicePool, related_name='memberOfMeta', on_delete=models.CASCADE)
meta_pool: MetaPool = models.ForeignKey(MetaPool, related_name='members', on_delete=models.CASCADE)
pool: 'models.ForeignKey[MetaPoolMember, ServicePool]' = models.ForeignKey(ServicePool, related_name='memberOfMeta', on_delete=models.CASCADE)
meta_pool: 'models.ForeignKey[MetaPoolMember, MetaPool]' = models.ForeignKey(MetaPool, related_name='members', on_delete=models.CASCADE)
priority = models.PositiveIntegerField(default=0)
enabled = models.BooleanField(default=True)
@ -225,5 +227,5 @@ class MetaPoolMember(UUIDModel):
db_table = 'uds__meta_pool_member'
app_label = 'uds'
def __str__(self):
def __str__(self) -> str:
return '{}/{} {} {}'.format(self.pool.name, self.meta_pool.name, self.priority, self.enabled)

View File

@ -34,7 +34,6 @@ import logging
import typing
from django.db import models
from django.db.models import signals
from uds.core.util import net
@ -123,11 +122,11 @@ class Network(UUIDModel, TaggingMixin): # type: ignore
self.net_string = netRange
self.save()
def __str__(self):
def __str__(self) -> str:
return u'Network {} ({}) from {} to {}'.format(self.name, self.net_string, net.longToIp(self.net_start), net.longToIp(self.net_end))
@staticmethod
def beforeDelete(sender, **kwargs):
def beforeDelete(sender, **kwargs) -> None:
from uds.core.util.permissions import clean
toDelete = kwargs['instance']
@ -137,4 +136,4 @@ class Network(UUIDModel, TaggingMixin): # type: ignore
clean(toDelete)
# Connects a pre deletion signal to Authenticator
signals.pre_delete.connect(Network.beforeDelete, sender=Network)
models.signals.pre_delete.connect(Network.beforeDelete, sender=Network)

View File

@ -33,8 +33,7 @@
import logging
import typing
from django.db import IntegrityError
from django.db.models import signals
from django.db import IntegrityError, models
from .managed_object_model import ManagedObjectModel
from .tag import TaggingMixin
@ -42,6 +41,7 @@ from .tag import TaggingMixin
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds.core import osmanagers
from uds.models import ServicePool
logger = logging.getLogger(__name__)
@ -50,7 +50,9 @@ class OSManager(ManagedObjectModel, TaggingMixin): # type: ignore
"""
An OS Manager represents a manager for responding requests for agents inside services.
"""
# pylint: disable=model-missing-unicode
# "fake" relations declarations for type checking
deployedServices: 'models.QuerySet[ServicePool]'
class Meta(ManagedObjectModel.Meta):
"""
@ -102,7 +104,7 @@ class OSManager(ManagedObjectModel, TaggingMixin): # type: ignore
return "{0} of type {1} (id:{2})".format(self.name, self.data_type, self.id)
@staticmethod
def beforeDelete(sender, **kwargs):
def beforeDelete(sender, **kwargs) -> None:
"""
Used to invoke the Service class "Destroy" before deleting it from database.
@ -122,5 +124,6 @@ class OSManager(ManagedObjectModel, TaggingMixin): # type: ignore
logger.debug('Before delete os manager %s', toDelete)
# : Connects a pre deletion signal to OS Manager
signals.pre_delete.connect(OSManager.beforeDelete, sender=OSManager)
models.signals.pre_delete.connect(OSManager.beforeDelete, sender=OSManager)

View File

@ -76,7 +76,7 @@ class Permissions(UUIDModel):
}.get(perm, _('None'))
@staticmethod
def addPermission(**kwargs):
def addPermission(**kwargs) -> 'Permissions':
"""
Adds a permission to an object and an user or group
"""
@ -113,7 +113,7 @@ class Permissions(UUIDModel):
object_type=object_type, object_id=object_id, permission=permission)
@staticmethod
def getPermissions(**kwargs):
def getPermissions(**kwargs) -> int:
"""
Retrieves the permission for a given object
It's mandatory to include at least object_type param
@ -149,29 +149,29 @@ class Permissions(UUIDModel):
return Permissions.PERMISSION_NONE
@staticmethod
def enumeratePermissions(object_type, object_id):
def enumeratePermissions(object_type, object_id) -> 'models.QuerySet[Permissions]':
"""
Get users permissions over object
"""
return Permissions.objects.filter(object_type=object_type, object_id=object_id)
@staticmethod
def cleanPermissions(object_type, object_id):
def cleanPermissions(object_type, object_id) -> None:
Permissions.objects.filter(object_type=object_type, object_id=object_id).delete()
@staticmethod
def cleanUserPermissions(user):
def cleanUserPermissions(user) -> None:
Permissions.objects.filter(user=user).delete()
@staticmethod
def cleanGroupPermissions(group):
def cleanGroupPermissions(group) -> None:
Permissions.objects.filter(group=group).delete()
@property
def permission_as_string(self):
def permission_as_string(self) -> str:
return Permissions.permissionAsString(self.permission)
def __str__(self):
def __str__(self) -> str:
return 'Permission {}, user {} group {} object_type {} object_id {} permission {}'.format(
self.uuid, self.user, self.group, self.object_type, self.object_id, Permissions.permissionAsString(self.permission)
)

View File

@ -86,11 +86,11 @@ class Provider(ManagedObjectModel, TaggingMixin): # type: ignore
def isInMaintenance(self) -> bool:
return self.maintenance_mode
def __str__(self):
def __str__(self) -> str:
return '{} of type {} (id:{})'.format(self.name, self.data_type, self.id)
@staticmethod
def beforeDelete(sender, **kwargs):
def beforeDelete(sender, **kwargs) -> None:
"""
Used to invoke the Provider class "Destroy" before deleting it from database.

View File

@ -105,5 +105,5 @@ class Proxy(UUIDModel, TaggingMixin): # type: ignore
return False
def __str__(self):
def __str__(self) -> str:
return 'Proxy {} on {}:{} '.format(self.name, self.host, self.port)

View File

@ -71,6 +71,9 @@ class Scheduler(models.Model):
owner_server = models.CharField(max_length=64, db_index=True, default='')
state = models.CharField(max_length=1, default=State.FOR_EXECUTE, db_index=True)
# primary key id declaration (for type checking)
id: int
class Meta:
"""
Meta class to declare default order and unique multiple field index

View File

@ -34,7 +34,6 @@ import logging
import typing
from django.db import models
from django.db.models import signals
from uds.core.environment import Environment
from uds.core.util import log
@ -59,10 +58,10 @@ class Service(ManagedObjectModel, TaggingMixin): # type: ignore
A Service represents an specidied type of service offered to final users, with it configuration (i.e. a KVM Base Machine for cloning
or a Terminal Server configuration).
"""
provider: 'Provider' = models.ForeignKey(Provider, related_name='services', on_delete=models.CASCADE)
provider: 'models.ForeignKey[Service, Provider]' = models.ForeignKey(Provider, related_name='services', on_delete=models.CASCADE)
# Proxy for this service
proxy: typing.Optional['Proxy'] = models.ForeignKey(Proxy, null=True, blank=True, related_name='services', on_delete=models.CASCADE)
proxy: 'models.ForeignKey[Service, Proxy]' = models.ForeignKey(Proxy, null=True, blank=True, related_name='services', on_delete=models.CASCADE)
token = models.CharField(max_length=32, default=None, null=True, blank=True, unique=True)
@ -182,4 +181,4 @@ class Service(ManagedObjectModel, TaggingMixin): # type: ignore
clean(toDelete)
# : Connects a pre deletion signal to Service
signals.pre_delete.connect(Service.beforeDelete, sender=Service)
models.signals.pre_delete.connect(Service.beforeDelete, sender=Service)

View File

@ -34,9 +34,9 @@ import typing
import logging
import pickle
from datetime import datetime, timedelta
from uds.core.util.states import publication
from django.db import models, transaction
from django.db.models import signals, QuerySet
from uds.core.environment import Environment
from uds.core.util import log
@ -53,7 +53,6 @@ from .transport import Transport
from .group import Group
from .image import Image
from .service_pool_group import ServicePoolGroup
from .calendar import Calendar
from .account import Account
from .util import NEVER
@ -62,9 +61,7 @@ from .util import getSqlDatetime
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds.models import UserService, ServicePoolPublication, User, Group, Proxy
from django.db.models import QuerySet
from uds.models import UserService, ServicePoolPublication, User, Group, Proxy, MetaPoolMember, CalendarAccess
logger = logging.getLogger(__name__)
@ -76,8 +73,8 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
name = models.CharField(max_length=128, default='')
short_name = models.CharField(max_length=32, default='')
comments = models.CharField(max_length=256, default='')
service: Service = models.ForeignKey(Service, null=True, blank=True, related_name='deployedServices', on_delete=models.CASCADE)
osmanager: typing.Optional[OSManager] = models.ForeignKey(OSManager, null=True, blank=True, related_name='deployedServices', on_delete=models.CASCADE)
service: 'models.ForeignKey[ServicePool, Service]' = models.ForeignKey(Service, null=True, blank=True, related_name='deployedServices', on_delete=models.CASCADE)
osmanager: 'models.ForeignKey[ServicePool, OSManager]' = models.ForeignKey(OSManager, null=True, blank=True, related_name='deployedServices', on_delete=models.CASCADE)
transports = models.ManyToManyField(Transport, related_name='deployedServices', db_table='uds__ds_trans')
assignedGroups = models.ManyToManyField(Group, related_name='deployedServices', db_table='uds__ds_grps')
state = models.CharField(max_length=1, default=states.servicePool.ACTIVE, db_index=True)
@ -89,17 +86,18 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
ignores_unused = models.BooleanField(default=False)
image: typing.Optional[Image] = models.ForeignKey(Image, null=True, blank=True, related_name='deployedServices', on_delete=models.SET_NULL)
image: 'models.ForeignKey[ServicePool, Image]' = models.ForeignKey(Image, null=True, blank=True, related_name='deployedServices', on_delete=models.SET_NULL)
servicesPoolGroup: typing.Optional[ServicePoolGroup] = models.ForeignKey(ServicePoolGroup, null=True, blank=True, related_name='servicesPools', on_delete=models.SET_NULL)
servicesPoolGroup: 'models.ForeignKey[ServicePool, ServicePoolGroup]' = models.ForeignKey(ServicePoolGroup, null=True, blank=True, related_name='servicesPools', on_delete=models.SET_NULL)
# Message if access denied
calendar_message = models.CharField(default='', max_length=256)
# Default fallback action for access
fallbackAccess = models.CharField(default=states.action.ALLOW, max_length=8)
# actionsCalendars = models.ManyToManyField(Calendar, related_name='actionsSP', through='CalendarAction')
# Usage accounting
account: typing.Optional[Account] = models.ForeignKey(Account, null=True, blank=True, related_name='servicesPools', on_delete=models.CASCADE)
account: 'models.ForeignKey[ServicePool, Account]' = models.ForeignKey(Account, null=True, blank=True, related_name='servicesPools', on_delete=models.CASCADE)
initial_srvs = models.PositiveIntegerField(default=0)
cache_l1_srvs = models.PositiveIntegerField(default=0)
@ -107,6 +105,12 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
max_srvs = models.PositiveIntegerField(default=0)
current_pub_revision = models.PositiveIntegerField(default=1)
# "fake" relations declarations for type checking
publications: 'models.QuerySet[ServicePoolPublication]'
memberOfMeta: 'models.QuerySet[MetaPoolMember]'
userServices: 'models.QuerySet[UserService]'
calendarAccess: 'models.QuerySet[CalendarAccess]'
# Meta service related
# meta_pools = models.ManyToManyField('self', symmetrical=False)
@ -121,6 +125,9 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
"""
Returns an environment valid for the record this object represents
"""
a = self.image
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id)
def activePublication(self) -> typing.Optional['ServicePoolPublication']:
@ -133,7 +140,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
None if there is no valid publication for this deployed service.
"""
try:
return self.publications.filter(state=states.publication.USABLE)[0]
return typing.cast(ServicePoolPublication, self.publications.filter(state=states.publication.USABLE)[0])
except Exception:
return None
@ -154,13 +161,13 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
return username, password
@staticmethod
def getRestrainedsQuerySet() -> QuerySet:
def getRestrainedsQuerySet() -> models.QuerySet:
from uds.models.user_service import UserService # pylint: disable=redefined-outer-name
from uds.core.util.config import GlobalConfig
from django.db.models import Count
if GlobalConfig.RESTRAINT_TIME.getInt() <= 0:
return [] # Do not perform any restraint check if we set the globalconfig to 0 (or less)
return ServicePool.objects.none() # Do not perform any restraint check if we set the globalconfig to 0 (or less)
date = typing.cast(datetime, getSqlDatetime()) - timedelta(seconds=GlobalConfig.RESTRAINT_TIME.getInt())
min_ = GlobalConfig.RESTRAINT_COUNT.getInt()
@ -174,8 +181,8 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
return ServicePool.objects.filter(pk__in=res)
@staticmethod
def getRestraineds() -> typing.Iterable['ServicePool']:
return ServicePool.getRestrainedsQuerySet().iterator()
def getRestraineds() -> typing.Iterator['ServicePool']:
return typing.cast(typing.Iterator['ServicePool'], ServicePool.getRestrainedsQuerySet().iterator())
@property
def is_meta(self) -> bool:
@ -234,7 +241,8 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
# Return the date
try:
if activePub and activePub.id != self.assignedUserServices().filter(user=forUser, state__in=states.userService.VALID_STATES)[0].publication.id:
found = typing.cast('UserService', self.assignedUserServices().filter(user=forUser, state__in=states.userService.VALID_STATES)[0])
if activePub and found.publication and activePub.id != found.publication.id:
ret = self.recoverValue('toBeReplacedIn')
if ret:
return pickle.loads(ret)
@ -499,7 +507,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
if pub:
pub.unpublish()
def cachedUserServices(self) -> 'QuerySet':
def cachedUserServices(self) -> 'models.QuerySet':
"""
':rtype uds.models.user_service.UserService'
Utility method to access the cached user services (level 1 and 2)
@ -509,7 +517,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
"""
return self.userServices.exclude(cache_level=0)
def assignedUserServices(self) -> 'QuerySet':
def assignedUserServices(self) -> 'models.QuerySet':
"""
Utility method to access the assigned user services
@ -518,7 +526,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
"""
return self.userServices.filter(cache_level=0)
def erroneousUserServices(self) -> 'QuerySet':
def erroneousUserServices(self) -> 'models.QuerySet':
"""
Utility method to locate invalid assigned user services.
@ -585,4 +593,4 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
# Connects a pre deletion signal to Authenticator
signals.pre_delete.connect(ServicePool.beforeDelete, sender=ServicePool)
models.signals.pre_delete.connect(ServicePool.beforeDelete, sender=ServicePool)

View File

@ -53,7 +53,7 @@ class ServicePoolGroup(UUIDModel):
name = models.CharField(max_length=128, default='', db_index=True, unique=True)
comments = models.CharField(max_length=256, default='')
priority = models.IntegerField(default=0, db_index=True)
image: Image = models.ForeignKey(Image, null=True, blank=True, related_name='servicesPoolsGroup', on_delete=models.SET_NULL)
image: 'models.ForeignKey[ServicePoolGroup, Image]' = models.ForeignKey(Image, null=True, blank=True, related_name='servicesPoolsGroup', on_delete=models.SET_NULL)
class Meta(UUIDModel.Meta):
"""
@ -63,7 +63,7 @@ class ServicePoolGroup(UUIDModel):
app_label = 'uds'
def __str__(self):
return 'Service Pool group {}({})'.format(self.name, self.comments)
return 'Service Pool group {}({}): {}'.format(self.name, self.comments, self.image.name)
@property
def as_dict(self) -> typing.Dict[str, typing.Any]:

View File

@ -35,7 +35,6 @@ import logging
import typing
from django.db import models
from django.db.models import signals
from uds.core.util.state import State
from uds.core.environment import Environment
@ -48,12 +47,13 @@ from .uuid_model import UUIDModel
if typing.TYPE_CHECKING:
from uds.core import services
from uds.models import UserService
logger = logging.getLogger(__name__)
class ServicePoolPublicationChangelog(models.Model):
publication: ServicePool = models.ForeignKey(ServicePool, on_delete=models.CASCADE, related_name='changelog')
publication: 'models.ForeignKey[ServicePoolPublication, ServicePool]' = models.ForeignKey(ServicePool, on_delete=models.CASCADE, related_name='changelog')
stamp = models.DateTimeField()
revision = models.PositiveIntegerField(default=1)
log = models.TextField(default='')
@ -72,7 +72,7 @@ class ServicePoolPublication(UUIDModel):
"""
A deployed service publication keep track of data needed by services that needs "preparation". (i.e. Virtual machine --> base machine --> children of base machines)
"""
deployed_service: ServicePool = models.ForeignKey(ServicePool, on_delete=models.CASCADE, related_name='publications')
deployed_service: 'models.ForeignKey[ServicePoolPublication, ServicePool]' = models.ForeignKey(ServicePool, on_delete=models.CASCADE, related_name='publications')
publish_date = models.DateTimeField(db_index=True)
# data_type = models.CharField(max_length=128) # The data type is specified by the service itself
data = models.TextField(default='')
@ -87,6 +87,10 @@ class ServicePoolPublication(UUIDModel):
state_date = models.DateTimeField()
revision = models.PositiveIntegerField(default=1)
# "fake" relations declarations for type checking
userServices: 'models.QuerySet[UserService]'
class Meta(UUIDModel.Meta):
"""
Meta class to declare default order and unique multiple field index
@ -207,4 +211,4 @@ class ServicePoolPublication(UUIDModel):
return 'Publication {}, rev {}, state {}'.format(self.deployed_service.name, self.revision, State.toString(self.state))
# Connects a pre deletion signal to Authenticator
signals.pre_delete.connect(ServicePoolPublication.beforeDelete, sender=ServicePoolPublication)
models.signals.pre_delete.connect(ServicePoolPublication.beforeDelete, sender=ServicePoolPublication)

View File

@ -63,7 +63,7 @@ class StatsCounters(models.Model):
app_label = 'uds'
@staticmethod
def get_grouped(owner_type: typing.Union[int, typing.Iterable[int]], counter_type: int, **kwargs) -> typing.Iterable: # pylint: disable=too-many-locals
def get_grouped(owner_type: typing.Union[int, typing.Iterable[int]], counter_type: int, **kwargs) -> 'models.QuerySet[StatsCounters]': # pylint: disable=too-many-locals
"""
Returns the average stats grouped by interval for owner_type and owner_id (optional)
@ -146,7 +146,7 @@ class StatsCounters(models.Model):
logger.debug('Stats query: %s', query)
# We use result as an iterator
return StatsCounters.objects.raw(query)
return typing.cast('models.QuerySet[StatsCounters]', StatsCounters.objects.raw(query))
def __str__(self):
return u"Counter of {}({}): {} - {} - {}".format(self.owner_type, self.owner_id, self.stamp, self.counter_type, self.value)

View File

@ -67,9 +67,9 @@ class StatsEvents(models.Model):
app_label = 'uds'
@staticmethod
def get_stats(owner_type: typing.Union[int, typing.Iterable[int]], event_type: typing.Union[int, typing.Iterable[int]], **kwargs) -> models.QuerySet:
def get_stats(owner_type: typing.Union[int, typing.Iterable[int]], event_type: typing.Union[int, typing.Iterable[int]], **kwargs) -> 'models.QuerySet[StatsEvents]':
"""
Returns the average stats grouped by interval for owner_type and owner_id (optional)
Returns a queryset with the average stats grouped by interval for owner_type and owner_id (optional)
Note: if someone cant get this more optimized, please, contribute it!
"""

View File

@ -56,4 +56,4 @@ class Storage(models.Model):
app_label = 'uds'
def __str__(self):
return '{} {} = {}, {}'.format(self.owner, self.key, self.data, '/'.join([self.attr1]))
return '{} {} > str= {}, {}'.format(self.owner, self.key, self.data, '/'.join([self.attr1]))

View File

@ -57,10 +57,10 @@ class Tag(UUIDModel):
app_label = 'uds'
@property
def vtag(self):
def vtag(self) -> str:
return self.tag.capitalize()
def __str__(self):
def __str__(self) -> str:
return 'Tag: {} {}'.format(self.uuid, self.tag)

View File

@ -102,7 +102,7 @@ class TicketStore(UUIDModel):
data: str,
validatorFnc: typing.Optional[ValidatorType] = None,
validity: int = DEFAULT_VALIDITY,
owner: typing.Optional[str] = owner,
owner: typing.Optional[str] = None,
secure: bool = False
) -> None:
"""
@ -119,6 +119,7 @@ class TicketStore(UUIDModel):
t.data = pickle.dumps(data)
t.stamp = getSqlDatetime()
t.validity = validity
t.owner = owner
t.save()
except TicketStore.DoesNotExist:
TicketStore.objects.create(uuid=uuid, stamp=getSqlDatetime(), data=pickle.dumps(data), validator=validator, validity=validity)

View File

@ -34,7 +34,6 @@ import logging
import typing
from django.db import models
from django.db.models import signals
from uds.core import transports
@ -43,6 +42,10 @@ from uds.core.util import net
from .managed_object_model import ManagedObjectModel
from .tag import TaggingMixin
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds.models import Network
logger = logging.getLogger(__name__)
@ -59,6 +62,10 @@ class Transport(ManagedObjectModel, TaggingMixin):
# We store allowed oss as a comma-separated list
allowed_oss = models.CharField(max_length=255, default='')
# "fake" relations declarations for type checking
networks: 'models.QuerySet[Network]'
class Meta(ManagedObjectModel.Meta):
"""
Meta class to declare default order
@ -69,7 +76,7 @@ class Transport(ManagedObjectModel, TaggingMixin):
def getInstance(self, values: typing.Optional[typing.Dict[str, str]] = None) -> 'transports.Transport':
return typing.cast('transports.Transport', super().getInstance(values=values))
def getType(self) -> typing.Type['transports.Transport']:
def getType(self) -> 'typing.Type[transports.Transport]':
"""
Get the type of the object this record represents.
@ -121,7 +128,7 @@ class Transport(ManagedObjectModel, TaggingMixin):
return True
return False
def __str__(self):
def __str__(self) -> str:
return '{} of type {} (id:{})'.format(self.name, self.data_type, self.id)
@staticmethod
@ -148,4 +155,4 @@ class Transport(ManagedObjectModel, TaggingMixin):
clean(toDelete)
# : Connects a pre deletion signal to OS Manager
signals.pre_delete.connect(Transport.beforeDelete, sender=Transport)
models.signals.pre_delete.connect(Transport.beforeDelete, sender=Transport)

View File

@ -56,5 +56,5 @@ class UniqueId(models.Model):
ordering = ('-seq',)
app_label = 'uds'
def __str__(self):
def __str__(self) -> str:
return u"{0} {1}.{2}, assigned is {3}".format(self.owner, self.basename, self.seq, self.assigned)

View File

@ -70,6 +70,9 @@ class User(UUIDModel):
parent = models.CharField(max_length=50, default=None, null=True)
created = models.DateTimeField(default=getSqlDatetime, blank=True)
# "fake" relations declarations for type checking
groups: 'models.QuerySet[Group]'
class Meta(UUIDModel.Meta):
"""
Meta class to declare default order and unique multiple field index
@ -154,7 +157,7 @@ class User(UUIDModel):
usr = self
grps: typing.List[int] = []
g: 'Group'
for g in usr.groups.filter(is_meta=False):
grps.append(g.id)
yield g
@ -164,17 +167,18 @@ class User(UUIDModel):
.annotate(number_groups=Count('groups')) # g.groups.count()
.annotate(number_belongs_meta=Count('groups', filter=Q(groups__id__in=grps))) # g.groups.filter(id__in=grps).count()
):
numberGroupsBelongingInMeta: int = g.number_belongs_meta
numberGroupsBelongingInMeta: int = g.number_belongs_meta
logger.debug('gn = %s', numberGroupsBelongingInMeta)
logger.debug('groups count: %s', g.number_groups)
logger.debug('groups count: %s', g.number_groups)
if g.meta_if_any is True and numberGroupsBelongingInMeta > 0:
numberGroupsBelongingInMeta = g.number_groups
logger.debug('gn after = %s', numberGroupsBelongingInMeta)
if numberGroupsBelongingInMeta == g.number_groups: # If a meta group is empty, all users belongs to it. we can use gn != 0 to check that if it is empty, is not valid
# If a meta group is empty, all users belongs to it. we can use gn != 0 to check that if it is empty, is not valid
if numberGroupsBelongingInMeta == g.number_groups:
# This group matches
yield g

View File

@ -52,5 +52,5 @@ class UserPreference(models.Model):
class Meta:
app_label = 'uds'
def __str__(self):
def __str__(self) -> str:
return '{}.{} = "{}" for user {}'.format(self.module, self.name, self.value, self.user)

View File

@ -65,8 +65,9 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
# The reference to deployed service is used to accelerate the queries for different methods, in fact its redundant cause we can access to the deployed service
# through publication, but queries are much more simple
deployed_service: ServicePool = models.ForeignKey(ServicePool, on_delete=models.CASCADE, related_name='userServices')
publication: typing.Optional[ServicePoolPublication] = models.ForeignKey(ServicePoolPublication, on_delete=models.CASCADE, null=True, blank=True, related_name='userServices')
deployed_service: 'models.ForeignKey[UserService, ServicePool]' = models.ForeignKey(ServicePool, on_delete=models.CASCADE, related_name='userServices')
publication: 'models.ForeignKey[UserService, ServicePoolPublication]' = models.ForeignKey(
ServicePoolPublication, on_delete=models.CASCADE, null=True, blank=True, related_name='userServices')
unique_id = models.CharField(max_length=128, default='', db_index=True) # User by agents to locate machine
friendly_name = models.CharField(max_length=128, default='')
@ -76,7 +77,8 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
state_date = models.DateTimeField(db_index=True)
creation_date = models.DateTimeField(db_index=True)
data = models.TextField(default='')
user: User = models.ForeignKey(User, on_delete=models.CASCADE, related_name='userServices', null=True, blank=True, default=None)
user: 'models.ForeignKey[UserService, User]' = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='userServices', null=True, blank=True, default=None)
in_use = models.BooleanField(default=False)
in_use_date = models.DateTimeField(default=NEVER)
cache_level = models.PositiveSmallIntegerField(db_index=True, default=0) # Cache level must be 1 for L1 or 2 for L2, 0 if it is not cached service
@ -86,6 +88,8 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
cluster_node = models.CharField(max_length=128, default=None, blank=True, null=True, db_index=True)
# "fake" relations declarations for type checking
properties: 'models.QuerySet[UserServiceProperty]'
class Meta(UUIDModel.Meta):
"""
@ -163,7 +167,8 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
logger.exception('Got exception at getInstance of an userService %s (seems that publication does not exists!)', self)
if serviceInstance.deployedType is None:
raise Exception('Class {0} needs deployedType but it is not defined!!!'.format(serviceInstance.__class__.__name__))
us = serviceInstance.deployedType(self.getEnvironment(), service=serviceInstance, publication=publicationInstance, osmanager=osmanagerInstance, dbservice=self)
us = serviceInstance.deployedType(self.getEnvironment(), service=serviceInstance,
publication=publicationInstance, osmanager=osmanagerInstance, dbservice=self)
if self.data != '' and self.data is not None:
try:
us.unserialize(self.data)
@ -376,7 +381,8 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
# 1.- If do not have any account associated, do nothing
# 2.- If called but already accounting, do nothing
# 3.- If called and not accounting, start accounting
if self.deployed_service.account is None or hasattr(self, 'accounting'): # accounting comes from AccountUsage, and is a OneToOneRelation with UserService
# accounting comes from AccountUsage, and is a OneToOneRelation with UserService
if self.deployed_service.account is None or hasattr(self, 'accounting'):
return
self.deployed_service.account.startUsageAccounting(self)

View File

@ -57,5 +57,5 @@ class UserServiceProperty(models.Model): # pylint: disable=too-many-public-meth
unique_together = (('name', 'user_service'),)
app_label = 'uds'
def __str__(self):
def __str__(self) -> str:
return "Property of {}. {}={}".format(self.user_service.pk, self.name, self.value)

View File

@ -45,6 +45,9 @@ class UUIDModel(models.Model):
"""
uuid = models.CharField(max_length=50, default=None, null=True, unique=True)
# Automatic field from Model without a defined specific primary_key
id: int
class Meta: # pylint: disable=too-few-public-methods
abstract = True

View File

@ -43,17 +43,18 @@ from uds.core.managers import userServiceManager
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from django.http import HttpRequest # pylint: disable=ungrouped-imports
from uds.core.util.request import ExtendedHttpRequest
from uds.core.util.tools import DictAsObj
logger = logging.getLogger(__name__)
def getServicesData(request: 'HttpRequest') -> typing.Dict[str, typing.Any]: # pylint: disable=too-many-locals, too-many-branches, too-many-statements
def getServicesData(request: 'ExtendedHttpRequest') -> typing.Dict[str, typing.Any]: # pylint: disable=too-many-locals, too-many-branches, too-many-statements
"""Obtains the service data dictionary will all available services for this request
Arguments:
request {HttpRequest} -- request from where to xtract credentials
request {ExtendedHttpRequest} -- request from where to xtract credentials
Returns:
typing.Dict[str, typing.Any] -- Keys has this:
@ -65,7 +66,9 @@ def getServicesData(request: 'HttpRequest') -> typing.Dict[str, typing.Any]: #
"""
# Session data
os: typing.Dict[str, str] = request.os
os: 'DictAsObj' = request.os
if not request.user:
return {}
# We look for services for this authenticator groups. User is logged in in just 1 authenticator, so his groups must coincide with those assigned to ds
groups = list(request.user.getGroups())