Several Fixes:

* Upgraded typing information on models
* Removed unused DBFile
* renamed osmanager.png wrong name
This commit is contained in:
Adolfo Gómez García 2022-10-01 06:45:41 +02:00
parent 8c40320b64
commit 57f2c35af0
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
49 changed files with 375 additions and 226 deletions

View File

@ -129,7 +129,7 @@ class Authenticators(ModelHandler):
'values': [gui.choiceItem('', _('None'))]
+ gui.sortedChoices(
[
gui.choiceItem(v.uuid, v.name)
gui.choiceItem(v.uuid or '', v.name)
for v in MFA.objects.all()
]
),

View File

@ -97,6 +97,7 @@ class Module(UserInterface, Environmentable, Serializable):
Environmentable is a base class that provides utility method to access a separate Environment for every single
module.
"""
__slots__ = ['_uuid']
# Import variable indicating this module is a base class not a real module
# Note that Module is not a real module, but a base class for all modules so isBase is not used on this class
@ -184,12 +185,25 @@ class Module(UserInterface, Environmentable, Serializable):
Base 64 encoded or raw image, obtained from the specified file at
'iconFile' class attribute
"""
file_ = open(
os.path.dirname(typing.cast(str, sys.modules[cls.__module__].__file__)) + '/' + cls.iconFile,
'rb',
)
data = file_.read()
file_.close()
try:
with open(
os.path.dirname(typing.cast(str, sys.modules[cls.__module__].__file__))
+ '/'
+ cls.iconFile,
'rb',
) as f:
data = f.read()
except Exception as e:
logger.error('Error reading icon file for module %s: %s', cls.type(), e)
# blank png bytes
data = codecs.decode(
(
b'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAY0lEQVR42u3QAREAAAQEMJKL'
b'/nI4W4R1KlOPtQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAg'
b'AABAgQIECBAgAABAgQIECBAgAABAgQIEHDfAvLdn4FABR1mAAAAAElFTkSuQmCC'
),
'base64',
)
return data

View File

@ -1,7 +1,8 @@
# Generated by Django 4.1 on 2022-09-01 14:46
# Generated by Django 4.1 on 2022-10-01 06:23
from django.db import migrations, models
import django.db.models.deletion
import uds.core.util.model
import uds.models.notifications
import uds.models.user_service_session
import uds.models.util
@ -52,7 +53,9 @@ class Migration(migrations.Migration):
(
"uuid",
models.CharField(
default=None, max_length=50, null=True, unique=True
default=uds.core.util.model.generateUuid,
max_length=50,
unique=True,
),
),
("data_type", models.CharField(max_length=128)),
@ -66,7 +69,6 @@ class Migration(migrations.Migration):
default=uds.models.notifications.NotificationLevel["ERROR"]
),
),
("tags", models.ManyToManyField(to="uds.tag")),
],
options={
"db_table": "uds_notify_prov",
@ -115,6 +117,9 @@ class Migration(migrations.Migration):
"db_table": "uds__user_service_session",
},
),
migrations.DeleteModel(
name="DBFile",
),
migrations.RemoveField(
model_name="authenticator",
name="visible",
@ -175,6 +180,125 @@ class Migration(migrations.Migration):
name="comments",
field=models.CharField(default="", max_length=256),
),
migrations.AlterField(
model_name="account",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="accountusage",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="authenticator",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="calendar",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="calendaraccess",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="calendaraccessmeta",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="calendaraction",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="calendarrule",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="group",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="image",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="metapool",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="metapoolmember",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="mfa",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="network",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="osmanager",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="permissions",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="provider",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="service",
name="token",
@ -182,6 +306,55 @@ class Migration(migrations.Migration):
blank=True, default=None, max_length=64, null=True, unique=True
),
),
migrations.AlterField(
model_name="service",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="servicepool",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="servicepoolgroup",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="servicepoolpublication",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="tag",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="ticketstore",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="transport",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="tunneltoken",
name="ip",
@ -192,11 +365,25 @@ class Migration(migrations.Migration):
name="ip_from",
field=models.CharField(max_length=128),
),
migrations.AlterField(
model_name="user",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.AlterField(
model_name="userservice",
name="src_ip",
field=models.CharField(default="", max_length=128),
),
migrations.AlterField(
model_name="userservice",
name="uuid",
field=models.CharField(
default=uds.core.util.model.generateUuid, max_length=50, unique=True
),
),
migrations.DeleteModel(
name="Proxy",
),
@ -218,6 +405,11 @@ class Migration(migrations.Migration):
to="uds.service",
),
),
migrations.AddField(
model_name="notifier",
name="tags",
field=models.ManyToManyField(to="uds.tag"),
),
migrations.AddConstraint(
model_name="userservicesession",
constraint=models.UniqueConstraint(

View File

@ -106,9 +106,6 @@ from .account_usage import AccountUsage
# Tagging
from .tag import Tag, TaggingMixin
# Utility
from .dbfile import DBFile
# Tokens
from .actor_token import ActorToken
from .tunnel_token import TunnelToken

View File

@ -55,7 +55,7 @@ class Account(UUIDModel, TaggingMixin):
comments = models.CharField(max_length=256, default='')
# "fake" declarations for type checking
objects: 'models.manager.Manager["Account"]'
#objects: 'models.manager.Manager["Account"]'
usages: 'models.manager.RelatedManager[AccountUsage]'
def startUsageAccounting(self, userService: 'UserService') -> typing.Optional['AccountUsage']:

View File

@ -54,7 +54,7 @@ class AccountUsage(UUIDModel):
"""
# "fake" declarations for type checking
objects: 'models.manager.Manager["AccountUsage"]'
# objects: 'models.manager.Manager["AccountUsage"]'
user_name = models.CharField(max_length=128, db_index=True, default='')
user_uuid = models.CharField(max_length=50, db_index=True, default='')
@ -62,7 +62,7 @@ class AccountUsage(UUIDModel):
pool_uuid = models.CharField(max_length=50, db_index=True, default='')
start = models.DateTimeField(default=NEVER)
end = models.DateTimeField(default=NEVER)
user_service: 'models.OneToOneField["AccountUsage", UserService]' = (
user_service: 'models.OneToOneField[UserService | None]' = (
models.OneToOneField(
UserService,
null=True,
@ -71,7 +71,7 @@ class AccountUsage(UUIDModel):
on_delete=models.SET_NULL,
)
)
account: 'models.ForeignKey["AccountUsage", Account]' = models.ForeignKey(
account: 'models.ForeignKey[Account]' = models.ForeignKey(
Account, related_name='usages', on_delete=models.CASCADE
)

View File

@ -50,7 +50,7 @@ class ActorToken(models.Model):
stamp = models.DateTimeField() # Date creation or validation of this entry
# "fake" declarations for type checking
objects: 'models.manager.Manager[ActorToken]'
# objects: 'models.manager.Manager[ActorToken]'
class Meta:
app_label = 'uds'

View File

@ -76,7 +76,7 @@ class Authenticator(ManagedObjectModel, TaggingMixin):
net_filtering = models.CharField(max_length=1, default=NO_FILTERING, db_index=True)
# "fake" relations declarations for type checking
objects: 'models.manager.Manager["Authenticator"]'
# objects: 'models.manager.Manager["Authenticator"]'
users: 'models.manager.RelatedManager[User]'
groups: 'models.manager.RelatedManager[Group]'
@ -163,7 +163,7 @@ class Authenticator(ManagedObjectModel, TaggingMixin):
Raises:
"""
user: 'User'
realName = realName if realName is None else username
realName = realName or username
user, _ = self.users.get_or_create(
name=username,
defaults={

View File

@ -49,13 +49,12 @@ class Cache(models.Model):
owner = models.CharField(max_length=128, db_index=True)
key = models.CharField(max_length=64, primary_key=True)
value = models.TextField(default='')
created = (
models.DateTimeField()
) # Date creation or validation of this entry. Set at write time
# Date creation or validation of this entry. Set at write time
created = models.DateTimeField()
validity = models.IntegerField(default=60) # Validity of this entry, in seconds
# "fake" relations declarations for type checking
objects: 'models.manager.Manager[Cache]'
# objects: 'models.manager.Manager[Cache]'
class Meta:
"""

View File

@ -52,7 +52,7 @@ class Calendar(UUIDModel, TaggingMixin):
modified = models.DateTimeField(auto_now=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager["Calendar"]'
# objects: 'models.manager.Manager["Calendar"]'
rules: 'models.manager.RelatedManager[CalendarRule]'
calendaraction_set: 'models.manager.RelatedManager[CalendarAction]'
calendaraccess_set: 'models.manager.RelatedManager[CalendarAccess]'

View File

@ -47,17 +47,17 @@ logger = logging.getLogger(__name__)
class CalendarAccess(UUIDModel):
calendar: 'models.ForeignKey[CalendarAccess, Calendar]' = models.ForeignKey(
calendar: 'models.ForeignKey[Calendar]' = models.ForeignKey(
Calendar, on_delete=models.CASCADE
)
service_pool: 'models.ForeignKey[CalendarAccess, ServicePool]' = models.ForeignKey(
service_pool: 'models.ForeignKey[ServicePool]' = models.ForeignKey(
ServicePool, related_name='calendarAccess', on_delete=models.CASCADE
)
access = models.CharField(max_length=8, default=states.action.DENY)
priority = models.IntegerField(default=0, db_index=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager[CalendarAccess]'
# objects: 'models.manager.Manager[CalendarAccess]'
class Meta:
"""

View File

@ -231,10 +231,10 @@ CALENDAR_ACTION_DICT: typing.Dict[str, typing.Dict] = {
class CalendarAction(UUIDModel):
calendar: 'models.ForeignKey[CalendarAction, Calendar]' = models.ForeignKey(
calendar: 'models.ForeignKey[Calendar]' = models.ForeignKey(
Calendar, on_delete=models.CASCADE
)
service_pool: 'models.ForeignKey[CalendarAction, ServicePool]' = models.ForeignKey(
service_pool: 'models.ForeignKey[ServicePool]' = models.ForeignKey(
ServicePool, on_delete=models.CASCADE
)
action = models.CharField(max_length=64, default='')
@ -252,7 +252,7 @@ class CalendarAction(UUIDModel):
)
# "fake" declarations for type checking
objects: 'models.manager.Manager[CalendarAction]'
# objects: 'models.manager.Manager[CalendarAction]'
class Meta:
"""

View File

@ -109,12 +109,12 @@ class CalendarRule(UUIDModel):
duration = models.IntegerField(default=0) # Duration in "duration_unit" units
duration_unit = models.CharField(choices=dunits, default='MINUTES', max_length=32)
calendar: 'models.ForeignKey["CalendarRule", Calendar]' = models.ForeignKey(
calendar: 'models.ForeignKey[Calendar]' = models.ForeignKey(
Calendar, related_name='rules', on_delete=models.CASCADE
)
# "fake" declarations for type checking
objects: 'models.manager.Manager["CalendarRule"]'
# objects: 'models.manager.Manager["CalendarRule"]'
class Meta:
"""
@ -134,7 +134,11 @@ class CalendarRule(UUIDModel):
)
# If at end of interval is requested, displace dstart to match end of interval
dstart = self.start if not atEnd else self.start + datetime.timedelta(minutes=self.duration_as_minutes)
dstart = (
self.start
if not atEnd
else self.start + datetime.timedelta(minutes=self.duration_as_minutes)
)
if self.frequency == WEEKDAYS:
dw = []

View File

@ -53,7 +53,7 @@ class Config(models.Model):
help = models.CharField(max_length=256, default='')
# "fake" declarations for type checking
objects: 'models.manager.Manager[Config]'
# objects: 'models.manager.Manager[Config]'
class Meta:
"""

View File

@ -1,78 +0,0 @@
# -*- coding: utf-8 -*-
# Model based on https://github.com/llazzaro/django-scheduler
#
# Copyright (c) 2016-2020 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. 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.
"""
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
"""
import codecs
import logging
from django.db import models
from .uuid_model import UUIDModel
logger = logging.getLogger(__name__)
class DBFile(UUIDModel):
# Not indexed, used for cleanups only
owner = models.CharField(max_length=32, default='')
name = models.CharField(max_length=255, primary_key=True)
content = models.TextField(blank=True)
size = models.IntegerField(default=0)
created = models.DateTimeField()
modified = models.DateTimeField()
# "fake" declarations for type checking
objects: 'models.manager.Manager[DBFile]'
@property
def data(self) -> bytes:
try:
return codecs.decode(codecs.decode(self.content.encode(), 'base64'), 'zip')
except Exception:
logger.error('DBFile %s has errors and cannot be used', self.name)
try:
self.delete() # Autodelete, invalid...
except Exception:
logger.error('Could not even delete %s!!', self.name)
return b''
@data.setter
def data(self, value: bytes):
self.size = len(value)
self.content = codecs.encode(codecs.encode(value, 'zip'), 'base64').decode()
def __str__(self) -> str:
return 'File: {} {} {} {}'.format(
self.name, self.size, self.created, self.modified
)

View File

@ -59,7 +59,7 @@ class DelayedTask(models.Model):
execution_time = models.DateTimeField(db_index=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager[DelayedTask]'
# objects: 'models.manager.Manager[DelayedTask]'
class Meta:
"""

View File

@ -56,7 +56,7 @@ class Group(UUIDModel):
This class represents a group, associated with one authenticator
"""
manager: 'models.ForeignKey["Group", Authenticator]' = UnsavedForeignKey(
manager: 'models.ForeignKey[Authenticator]' = UnsavedForeignKey(
Authenticator, on_delete=models.CASCADE, related_name='groups'
)
name = models.CharField(max_length=128, db_index=True)
@ -69,7 +69,7 @@ class Group(UUIDModel):
created = models.DateTimeField(default=getSqlDatetime, blank=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager["Group"]'
# objects: 'models.manager.Manager["Group"]'
deployedServices: 'models.manager.RelatedManager[ServicePool]'
permissions: 'models.manager.RelatedManager[Permissions]'

View File

@ -71,7 +71,7 @@ class Image(UUIDModel):
height = models.IntegerField(default=0)
# "fake" declarations for type checking
objects: 'models.manager.RelatedManager["Image"]'
# objects: 'models.manager.RelatedManager["Image"]'
deployedServices: 'models.manager.RelatedManager[ServicePool]'
metaPools: 'models.manager.RelatedManager[MetaPool]'

View File

@ -55,7 +55,7 @@ class Log(models.Model):
data = models.CharField(max_length=255, default='')
# "fake" declarations for type checking
objects: 'models.manager.Manager[Log]'
# objects: 'models.manager.Manager[Log]'
class Meta:
"""

View File

@ -68,9 +68,11 @@ class ManagedObjectModel(UUIDModel):
"""
Returns an environment valid for the record this object represents
"""
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id)
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id) # type: ignore
def deserialize(self, obj: Module, values: typing.Optional[typing.Mapping[str, str]]):
def deserialize(
self, obj: Module, values: typing.Optional[typing.Mapping[str, str]]
):
"""
Conditionally deserializes obj if not initialized via user interface and data holds something
"""

View File

@ -129,7 +129,7 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
ha_policy = models.SmallIntegerField(default=HA_POLICY_DISABLED)
# "fake" declarations for type checking
objects: 'models.BaseManager["MetaPool"]'
# objects: 'models.BaseManager["MetaPool"]'
calendarAccess: 'models.QuerySet[CalendarAccessMeta]'
members: 'models.QuerySet["MetaPoolMember"]'
@ -182,7 +182,9 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
access = self.fallbackAccess
# Let's see if we can access by current datetime
for ac in sorted(self.calendarAccess.all(), key=operator.attrgetter('priority')):
for ac in sorted(
self.calendarAccess.all(), key=operator.attrgetter('priority')
):
if CalendarChecker(ac.calendar).check(chkDateTime):
access = ac.access
break # Stops on first rule match found
@ -278,10 +280,10 @@ signals.pre_delete.connect(MetaPool.beforeDelete, sender=MetaPool)
class MetaPoolMember(UUIDModel):
pool: 'models.ForeignKey["MetaPoolMember", ServicePool]' = models.ForeignKey(
pool: 'models.ForeignKey[ServicePool]' = models.ForeignKey(
ServicePool, related_name='memberOfMeta', on_delete=models.CASCADE
)
meta_pool: 'models.ForeignKey["MetaPoolMember", MetaPool]' = models.ForeignKey(
meta_pool: 'models.ForeignKey[MetaPool]' = models.ForeignKey(
MetaPool, related_name='members', on_delete=models.CASCADE
)
priority = models.PositiveIntegerField(default=0)

View File

@ -51,12 +51,14 @@ class MFA(ManagedObjectModel, TaggingMixin): # type: ignore
An OS Manager represents a manager for responding requests for agents inside services.
"""
# "fake" declarations for type checking
objects: 'models.BaseManager[MFA]'
authenticators: 'models.manager.RelatedManager[Authenticator]'
# Time to remember the device MFA in hours
remember_device = models.IntegerField(default=0)
# Limit of time for this MFA to be used, in seconds
validity = models.IntegerField(default=0)
remember_device = models.IntegerField(default=0) # Time to remember the device MFA in hours
validity = models.IntegerField(default=0) # Limit of time for this MFA to be used, in seconds
# "fake" declarations for type checking
# objects: 'models.BaseManager[MFA]'
authenticators: 'models.manager.RelatedManager[Authenticator]'
def getInstance(
self, values: typing.Optional[typing.Dict[str, str]] = None
@ -64,15 +66,15 @@ class MFA(ManagedObjectModel, TaggingMixin): # type: ignore
return typing.cast('mfas.MFA', super().getInstance(values=values))
def getType(self) -> typing.Type['mfas.MFA']:
"""
Get the type of the object this record represents.
"""Get the type of the object this record represents.
The type is Python type, it obtains this OsManagersFactory and associated record field.
The type is a Python type, it obtains this MFA and associated record field.
Returns:
The python type for this record object
:note: We only need to get info from this, not access specific data (class specific info)
Note:
We only need to get info from this, not access specific data (class specific info)
"""
# We only need to get info from this, not access specific data (class specific info)
from uds.core import mfas
@ -100,7 +102,11 @@ class MFA(ManagedObjectModel, TaggingMixin): # type: ignore
s.destroy()
s.env.clearRelatedData()
except Exception as e:
logger.error('Error processing deletion of notifier %s: %s (forced deletion)', toDelete.name, e)
logger.error(
'Error processing deletion of notifier %s: %s (forced deletion)',
toDelete.name,
e,
)
logger.debug('Before delete mfa provider %s', toDelete)

View File

@ -63,7 +63,7 @@ class Network(UUIDModel, TaggingMixin): # type: ignore
)
# "fake" declarations for type checking
objects: 'models.manager.Manager[Network]'
# objects: 'models.manager.Manager[Network]'
class Meta(UUIDModel.Meta):
"""

View File

@ -73,7 +73,7 @@ class Notification(models.Model):
processed = models.BooleanField(default=False)
# "fake" declarations for type checking
objects: 'models.BaseManager[Notification]'
# objects: 'models.BaseManager[Notification]'
class Meta:
"""

View File

@ -52,7 +52,7 @@ class OSManager(ManagedObjectModel, TaggingMixin):
"""
# "fake" declarations for type checking
objects: 'models.manager.Manager[OSManager]'
# objects: 'models.manager.Manager[OSManager]'
deployedServices: 'models.manager.RelatedManager[ServicePool]'
class Meta(ManagedObjectModel.Meta):

View File

@ -84,7 +84,7 @@ class Permissions(UUIDModel):
permission = models.SmallIntegerField(default=PERMISSION_NONE, db_index=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager[Permissions]'
# objects: 'models.manager.Manager[Permissions]'
@staticmethod
def permissionAsString(perm: int) -> str:

View File

@ -56,7 +56,7 @@ class Provider(ManagedObjectModel, TaggingMixin): # type: ignore
maintenance_mode = models.BooleanField(default=False, db_index=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager[Provider]'
# objects: 'models.manager.Manager[Provider]'
services: 'models.manager.RelatedManager[Service]'
class Meta(ManagedObjectModel.Meta):

View File

@ -73,7 +73,7 @@ class Scheduler(models.Model):
# primary key id declaration (for type checking)
# "fake" declarations for type checking
objects: 'models.manager.Manager[Scheduler]'
# objects: 'models.manager.Manager[Scheduler]'
id: int # Primary key (Autogenerated by model, just for type checking)
class Meta:
@ -87,7 +87,7 @@ class Scheduler(models.Model):
"""
Returns an environment valid for the record this object represents
"""
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id)
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id) # type: ignore
def getInstance(self) -> typing.Optional[jobs.Job]:
"""

View File

@ -74,7 +74,7 @@ class Service(ManagedObjectModel, TaggingMixin): # type: ignore
Server configuration).
"""
provider: 'models.ForeignKey["Service", Provider]' = models.ForeignKey(
provider: 'models.ForeignKey[Provider]' = models.ForeignKey(
Provider, related_name='services', on_delete=models.CASCADE
)
@ -89,11 +89,10 @@ class Service(ManagedObjectModel, TaggingMixin): # type: ignore
_cachedInstance: typing.Optional['services.Service'] = None
# "fake" declarations for type checking
objects: 'models.manager.Manager["Service"]'
# objects: 'models.manager.Manager["Service"]'
deployedServices: 'models.manager.RelatedManager[ServicePool]'
aliases: 'models.manager.RelatedManager[ServiceTokenAlias]'
class Meta(ManagedObjectModel.Meta):
"""
Meta class to declare default order and unique multiple field index
@ -112,7 +111,7 @@ class Service(ManagedObjectModel, TaggingMixin): # type: ignore
Returns an environment valid for the record this object represents
"""
return Environment.getEnvForTableElement(
self._meta.verbose_name,
self._meta.verbose_name, # type: ignore
self.id,
{
'mac': unique.UniqueMacGenerator,
@ -194,11 +193,9 @@ class Service(ManagedObjectModel, TaggingMixin): # type: ignore
# Counts EVERYTHING for max limit checking
return self.max_services_count_type == 1
def __str__(self) -> str:
return '{} of type {} (id:{})'.format(self.name, self.data_type, self.id)
@staticmethod
def beforeDelete(sender, **kwargs) -> None:
"""

View File

@ -70,7 +70,7 @@ if typing.TYPE_CHECKING:
Group,
MetaPoolMember,
CalendarAccess,
CalendarAction
CalendarAction,
)
logger = logging.getLogger(__name__)
@ -84,14 +84,14 @@ 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: 'models.ForeignKey["ServicePool", Service]' = models.ForeignKey(
service: 'models.ForeignKey[Service | None]' = models.ForeignKey(
Service,
null=True,
blank=True,
related_name='deployedServices',
on_delete=models.CASCADE,
)
osmanager: 'models.ForeignKey["ServicePool", OSManager]' = models.ForeignKey(
osmanager: 'models.ForeignKey[OSManager | None]' = models.ForeignKey(
OSManager,
null=True,
blank=True,
@ -115,7 +115,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
ignores_unused = models.BooleanField(default=False)
image: 'models.ForeignKey["ServicePool", Image]' = models.ForeignKey(
image: 'models.ForeignKey[Image | None]' = models.ForeignKey(
Image,
null=True,
blank=True,
@ -123,14 +123,12 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
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,
)
servicesPoolGroup: 'models.ForeignKey[ServicePoolGroup | None]' = models.ForeignKey(
ServicePoolGroup,
null=True,
blank=True,
related_name='servicesPools',
on_delete=models.SET_NULL,
)
# Message if access denied
@ -139,7 +137,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
fallbackAccess = models.CharField(default=states.action.ALLOW, max_length=8)
# Usage accounting
account: 'models.ForeignKey["ServicePool", Account]' = models.ForeignKey(
account: 'models.ForeignKey[Account | None]' = models.ForeignKey(
Account,
null=True,
blank=True,
@ -162,7 +160,6 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
calendaraction_set: 'models.manager.RelatedManager[CalendarAction]'
changelog: 'models.manager.RelatedManager[ServicePoolPublicationChangelog]'
class Meta(UUIDModel.Meta):
"""
Meta class to declare the name of the table at database
@ -175,7 +172,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
"""
Returns an environment valid for the record this object represents
"""
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id)
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id) # type: ignore
def activePublication(self) -> typing.Optional['ServicePoolPublication']:
"""
@ -187,7 +184,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] # type: ignore # Slicing is not supported by pylance right now
return self.publications.filter(state=states.publication.USABLE)[0] # type: ignore # Slicing is not supported by pylance right now
except Exception:
return None
@ -316,12 +313,16 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
'UserService',
self.assignedUserServices().filter(
user=forUser, state__in=states.userService.VALID_STATES
)[0], # type: ignore # Slicing is not supported by pylance right now
)[
0
], # type: ignore # Slicing is not supported by pylance right now
)
if activePub and found.publication and activePub.id != found.publication.id:
ret = self.recoverValue('toBeReplacedIn')
if ret:
return pickle.loads(ret) # nosec: Value is safe because it is generated by the system
return pickle.loads( # nosec: Value is safe because it is generated by the system
ret
)
except Exception: # nosec: We don't want to fail if there is any exception
# logger.exception('Recovering publication death line')
pass
@ -337,7 +338,9 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
access = self.fallbackAccess
# Let's see if we can access by current datetime
for ac in sorted(self.calendarAccess.all(), key=operator.attrgetter('priority')):
for ac in sorted(
self.calendarAccess.all(), key=operator.attrgetter('priority')
):
if CalendarChecker(ac.calendar).check(chkDateTime):
access = ac.access
break # Stops on first rule match found
@ -498,6 +501,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
"""
if (
self.activePublication() is None
and self.service
and self.service.getType().publicationType is not None
):
raise InvalidServiceException()
@ -599,9 +603,9 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
)
servicePool: 'ServicePool'
for servicePool in query:
if (
typing.cast(typing.Any, servicePool).pubs_active
or servicePool.service.data_type in servicesNotNeedingPub
if typing.cast(typing.Any, servicePool).pubs_active or (
servicePool.service
and servicePool.service.data_type in servicesNotNeedingPub
):
yield servicePool
@ -661,7 +665,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
cachedValue is used to optimize (if known the number of assigned services, we can avoid to query the db)
"""
maxs = self.max_srvs
if maxs == 0:
if maxs == 0 and self.service:
maxs = self.service.getInstance().maxDeployed
if maxs <= 0:
@ -676,8 +680,10 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
return 100 * cachedValue // maxs
def testServer(self, host: str, port: typing.Union[str, int], timeout: float=4) -> bool:
return self.service.testServer(host, port, timeout)
def testServer(
self, host: str, port: typing.Union[str, int], timeout: float = 4
) -> bool:
return bool(self.service) and self.service.testServer(host, port, timeout)
# Utility for logging
def log(self, message: str, level: int = log.INFO) -> None:

View File

@ -54,7 +54,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: 'models.ForeignKey[ServicePoolGroup, Image]' = models.ForeignKey(
image: 'models.ForeignKey[Image | None]' = models.ForeignKey(
Image,
null=True,
blank=True,
@ -63,7 +63,7 @@ class ServicePoolGroup(UUIDModel):
)
# "fake" declarations for type checking
objects: 'models.manager.Manager[ServicePoolGroup]'
# objects: 'models.manager.Manager[ServicePoolGroup]'
class Meta(UUIDModel.Meta):
"""
@ -75,7 +75,7 @@ class ServicePoolGroup(UUIDModel):
def __str__(self) -> str:
return 'Service Pool group {}({}): {}'.format(
self.name, self.comments, self.image.name
self.name, self.comments, self.image.name if self.image else ''
)
@property

View File

@ -55,17 +55,15 @@ logger = logging.getLogger(__name__)
class ServicePoolPublicationChangelog(models.Model):
# This should be "servicePool"
publication: 'models.ForeignKey[ServicePoolPublicationChangelog, ServicePool]' = (
models.ForeignKey(
ServicePool, on_delete=models.CASCADE, related_name='changelog'
)
publication: 'models.ForeignKey[ServicePool]' = models.ForeignKey(
ServicePool, on_delete=models.CASCADE, related_name='changelog'
)
stamp = models.DateTimeField()
revision = models.PositiveIntegerField(default=1)
log = models.TextField(default='')
# "fake" declarations for type checking
objects: 'models.manager.Manager[ServicePoolPublicationChangelog]'
# objects: 'models.manager.Manager[ServicePoolPublicationChangelog]'
class Meta(UUIDModel.Meta):
"""
@ -86,10 +84,8 @@ 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: 'models.ForeignKey["ServicePoolPublication", ServicePool]' = (
models.ForeignKey(
ServicePool, on_delete=models.CASCADE, related_name='publications'
)
deployed_service: 'models.ForeignKey[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
@ -106,7 +102,7 @@ class ServicePoolPublication(UUIDModel):
revision = models.PositiveIntegerField(default=1)
# "fake" declarations for type checking
objects: 'models.manager.Manager["ServicePoolPublication"]'
# objects: 'models.manager.Manager["ServicePoolPublication"]'
userServices: 'models.manager.RelatedManager[UserService]'
class Meta(UUIDModel.Meta):
@ -122,7 +118,7 @@ class ServicePoolPublication(UUIDModel):
"""
Returns an environment valid for the record this object represents
"""
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id)
return Environment.getEnvForTableElement(self._meta.verbose_name, self.id) # type: ignore
def getInstance(self) -> 'services.Publication':
"""
@ -139,6 +135,8 @@ class ServicePoolPublication(UUIDModel):
Raises:
"""
if not self.deployed_service.service:
raise Exception('No service assigned to publication')
serviceInstance = self.deployed_service.service.getInstance()
osManager = self.deployed_service.osmanager
osManagerInstance = osManager.getInstance() if osManager else None

View File

@ -57,7 +57,7 @@ class StatsCounters(models.Model):
value = models.IntegerField(db_index=True, default=0)
# "fake" declarations for type checking
objects: 'models.manager.Manager[StatsCounters]'
# objects: 'models.manager.Manager[StatsCounters]'
class Meta:
"""
@ -125,7 +125,7 @@ class StatsCounters(models.Model):
floor = getSqlFnc('FLOOR')
if interval > 0:
q = q.extra(
q = q.extra( # nosec: SQL injection is not possible here, all values are integers
select={
'group_by_stamp': f'{floor}(stamp / {interval}) * {interval}',
},
@ -227,7 +227,7 @@ class StatsCounters(models.Model):
# fnc = getSqlFnc('MAX' if kwargs.get('use_max', False) else 'AVG')
query = (
'SELECT -1 as id,-1 as owner_id,-1 as owner_type,-1 as counter_type, '
'SELECT -1 as id,-1 as owner_id,-1 as owner_type,-1 as counter_type, ' # nosec: SQL injection is not possible here, all values are controlled
+ stampValue
+ '*{}'.format(interval)
+ ' AS stamp, '

View File

@ -60,7 +60,7 @@ class StatsEvents(models.Model):
fld4 = models.CharField(max_length=128, default='')
# "fake" declarations for type checking
objects: 'models.manager.Manager[StatsEvents]'
# objects: 'models.manager.Manager[StatsEvents]'
class Meta:
"""

View File

@ -51,7 +51,7 @@ class Storage(models.Model):
)
# "fake" declarations for type checking
objects: 'models.manager.Manager[Storage]'
# objects: 'models.manager.Manager[Storage]'
class Meta:
"""
@ -62,5 +62,5 @@ class Storage(models.Model):
def __str__(self) -> str:
return '{} {} > str= {}, {}'.format(
self.owner, self.key, self.data, '/'.join([self.attr1])
self.owner, self.key, self.data, '/'.join([self.attr1 or ''])
)

View File

@ -65,7 +65,7 @@ class Tag(UUIDModel):
tag = models.CharField(max_length=32, db_index=True, unique=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager["Tag"]'
# objects: 'models.manager.Manager["Tag"]'
# Every single related class has a relation with this
# Its inverse is "xxx_set" class

View File

@ -29,7 +29,7 @@
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
import datetime
import pickle
import pickle # nosec: Tickets are generated by us, so we know they are safe
import logging
import typing
@ -71,7 +71,7 @@ class TicketStore(UUIDModel):
) # Associated validator for this ticket
# "fake" declarations for type checking
objects: 'models.manager.Manager[TicketStore]'
# objects: 'models.manager.Manager[TicketStore]'
class InvalidTicket(Exception):
pass
@ -151,11 +151,11 @@ class TicketStore(UUIDModel):
data, typing.cast(str, owner).encode()
)
data = pickle.loads(data)
data = pickle.loads(data) # nosec: Tickets are generated by us, so we know they are safe
# If has validator, execute it
if t.validator:
validator: ValidatorType = pickle.loads(t.validator)
validator: ValidatorType = pickle.loads(t.validator) # nosec: Tickets are generated by us, so we know they are safe
if validator(data) is False:
raise TicketStore.InvalidTicket('Validation failed')
@ -194,7 +194,7 @@ class TicketStore(UUIDModel):
) -> str:
owner = cryptoManager().randomString(length=8)
data = {
'u': userService.user.uuid,
'u': userService.user.uuid if userService.user else '',
's': userService.uuid,
'h': host,
'p': port,
@ -259,7 +259,7 @@ class TicketStore(UUIDModel):
TicketStore.objects.filter(stamp__lt=cleanSince).delete()
def __str__(self) -> str:
data = pickle.loads(self.data) if self.owner != SECURED else '{Secure Ticket}'
data = pickle.loads(self.data) if self.owner != SECURED else '{Secure Ticket}' # nosec: Tickets are generated by us, so we know they are safe
return 'Ticket id: {}, Owner: {}, Stamp: {}, Validity: {}, Data: {}'.format(
self.uuid,

View File

@ -71,7 +71,7 @@ class Transport(ManagedObjectModel, TaggingMixin):
label = models.CharField(max_length=32, default='', db_index=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager[Transport]'
# objects: 'models.manager.Manager[Transport]'
deployedServices: 'models.manager.RelatedManager[ServicePool]'
networks: 'models.manager.RelatedManager[Network]'

View File

@ -48,7 +48,7 @@ class TunnelToken(models.Model):
stamp = models.DateTimeField() # Date creation or validation of this entry
# "fake" declarations for type checking
objects: 'models.manager.Manager[TunnelToken]'
# objects: 'models.manager.Manager[TunnelToken]'
class Meta:
app_label = 'uds'

View File

@ -50,7 +50,7 @@ class UniqueId(models.Model):
stamp = models.IntegerField(db_index=True, default=0)
# "fake" declarations for type checking
objects: 'models.manager.Manager[UniqueId]'
# objects: 'models.manager.Manager[UniqueId]'
class Meta:
"""

View File

@ -57,7 +57,7 @@ class User(UUIDModel):
This class represents a single user, associated with one authenticator
"""
manager: 'models.ForeignKey["User", Authenticator]' = UnsavedForeignKey(
manager: 'models.ForeignKey[Authenticator]' = UnsavedForeignKey(
Authenticator, on_delete=models.CASCADE, related_name='users'
)
name = models.CharField(max_length=128, db_index=True)
@ -79,7 +79,7 @@ class User(UUIDModel):
created = models.DateTimeField(default=getSqlDatetime, blank=True)
# "fake" declarations for type checking
objects: 'models.manager.Manager["User"]'
# objects: 'models.manager.Manager["User"]'
groups: 'models.manager.RelatedManager[Group]'
userServices: 'models.manager.RelatedManager[UserService]'
permissions: 'models.manager.RelatedManager[Permissions]'

View File

@ -51,7 +51,7 @@ class UserPreference(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='preferences')
# "fake" declarations for type checking
objects: 'models.manager.Manager[UserPreference]'
# objects: 'models.manager.Manager[UserPreference]'
class Meta:
app_label = 'uds'

View File

@ -71,18 +71,16 @@ 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: 'models.ForeignKey["UserService", ServicePool]' = models.ForeignKey(
deployed_service: 'models.ForeignKey["ServicePool"]' = models.ForeignKey(
ServicePool, on_delete=models.CASCADE, related_name='userServices'
)
publication: 'models.ForeignKey["UserService", ServicePoolPublication]' = (
models.ForeignKey(
publication: 'models.ForeignKey[ServicePoolPublication | None]' = 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
@ -116,7 +114,7 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
src_ip = models.CharField(max_length=128, default='')
# "fake" declarations for type checking
objects: 'models.manager.Manager["UserService"]'
# objects: 'models.manager.Manager["UserService"]'
properties: 'models.manager.RelatedManager[UserServiceProperty]'
sessions: 'models.manager.RelatedManager[UserServiceSession]'
accounting: 'AccountUsage'
@ -174,7 +172,7 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
(see related classes uds.core.util.unique_name_generator and uds.core.util.unique_mac_generator)
"""
return Environment.getEnvForTableElement(
self._meta.verbose_name,
self._meta.verbose_name, # type: ignore
self.id,
{
'mac': unique.UniqueMacGenerator,
@ -201,6 +199,8 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
"""
# We get the service instance, publication instance and osmanager instance
servicePool = self.deployed_service
if not servicePool.service:
raise Exception('Service not found')
serviceInstance = servicePool.service.getInstance()
if serviceInstance.needsManager is False or not servicePool.osmanager:
osmanagerInstance = None
@ -374,6 +374,8 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
:note: This method MUST be invoked by transport before using credentials passed to getJavascript.
"""
servicePool = self.deployed_service
if not servicePool.service:
raise Exception('Service not found')
serviceInstance = servicePool.service.getInstance()
if serviceInstance.needsManager is False or not servicePool.osmanager:
return (username, password)
@ -615,7 +617,7 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
Returns True if this user service does not needs an publication, or if this deployed service publication is the current one
"""
return (
self.deployed_service.service.getType().publicationType is None
(self.deployed_service.service and self.deployed_service.service.getType().publicationType is None)
or self.publication == self.deployed_service.activePublication()
)

View File

@ -53,7 +53,7 @@ class UserServiceProperty(models.Model): # pylint: disable=too-many-public-meth
)
# "fake" declarations for type checking
objects: 'models.manager.Manager[UserServiceProperty]'
# objects: 'models.manager.Manager[UserServiceProperty]'
class Meta:
"""

View File

@ -58,12 +58,12 @@ class UserServiceSession(models.Model): # pylint: disable=too-many-public-metho
start = models.DateTimeField(default=getSqlDatetime)
end = models.DateTimeField(null=True, blank=True)
user_service = models.ForeignKey(
user_service: 'models.ForeignKey[UserService]' = models.ForeignKey(
UserService, on_delete=models.CASCADE, related_name='sessions'
)
# "fake" declarations for type checking
objects: 'models.manager.Manager["UserServiceSession"]'
# objects: 'models.manager.Manager["UserServiceSession"]'
class Meta:
"""

View File

@ -55,14 +55,16 @@ class UnsavedForeignKey(models.ForeignKey):
def getSqlDatetime() -> datetime:
"""
Returns the current date/time of the database server.
"""Returns the current date/time of the database server.
We use this time as method of keeping all operations betwen different servers in sync.
We use this time as method to keep all operations betwen different servers in sync.
We support get database datetime for:
* mysql
* sqlite
Returns:
datetime: Current datetime of the database server
"""
if connection.vendor in ('mysql', 'microsoft'):
cursor = connection.cursor()
@ -72,7 +74,7 @@ def getSqlDatetime() -> datetime:
else 'SELECT CURRENT_TIMESTAMP'
)
cursor.execute(sentence)
date = cursor.fetchone()[0]
date = (cursor.fetchone() or [datetime.now()])[0]
else:
date = (
datetime.now()
@ -82,12 +84,19 @@ def getSqlDatetime() -> datetime:
def getSqlDatetimeAsUnix() -> int:
"""Returns the current date/time of the database server as unix timestamp
Returns:
int: Unix timestamp
"""
return int(mktime(getSqlDatetime().timetuple()))
def getSqlFnc(fncName: str) -> str:
"""
Convert different sql functions for different platforms
"""Convert different sql functions for different platforms
i.e. CEIL --> CEILING on mssql
"""
if connection.vendor == 'microsoft':
return {'CEIL': 'CEILING'}.get(fncName, fncName)

View File

@ -45,7 +45,7 @@ class UUIDModel(models.Model):
Base abstract model for models that require an uuid
"""
uuid = models.CharField(max_length=50, default=None, null=True, unique=True)
uuid = models.CharField(max_length=50, unique=True, default=generateUuid)
# Automatic field from Model without a defined specific primary_key
# Just a fake declaration to allow type checking
@ -58,9 +58,7 @@ class UUIDModel(models.Model):
return generateUuid()
# Override default save to add uuid
def save(
self, *args, **kwargs
):
def save(self, *args, **kwargs):
if not self.uuid:
self.uuid = self.genUuid()
elif self.uuid != self.uuid.lower():

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -36,6 +36,7 @@ from uds.core import services
from uds.core.ui import gui
from uds.core.util import validators
from uds.core.util.unique_id_generator import UniqueIDGenerator
from uds.core.util.unique_mac_generator import UniqueMacGenerator
from uds.core.util.cache import Cache
from uds.core.util.decorators import allowCache