diff --git a/src/pretix/base/migrations/0099_auto_20180912_1035.py b/src/pretix/base/migrations/0099_auto_20180912_1035.py new file mode 100644 index 0000000000..fea4153cea --- /dev/null +++ b/src/pretix/base/migrations/0099_auto_20180912_1035.py @@ -0,0 +1,40 @@ +# Generated by Django 2.1 on 2018-09-12 10:35 + +import django.db.models.deletion +from django.db import migrations, models + +import pretix.base.models.devices + + +class Migration(migrations.Migration): + + dependencies = [ + ('pretixbase', '0098_auto_20180731_1243_squashed_0100_item_require_approval'), + ] + + operations = [ + migrations.CreateModel( + name='Device', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('device_id', models.PositiveIntegerField()), + ('unique_serial', models.CharField(default=pretix.base.models.devices.generate_serial, max_length=190, unique=True)), + ('initialization_token', models.CharField(default=pretix.base.models.devices.generate_initialization_token, max_length=190, unique=True)), + ('api_token', models.CharField(max_length=190, null=True, unique=True)), + ('all_events', models.BooleanField(default=False, verbose_name='All events (including newly created ones)')), + ('name', models.CharField(max_length=190, verbose_name='Name')), + ('created', models.DateTimeField(auto_now_add=True, verbose_name='Setup date')), + ('initialized', models.DateTimeField(null=True, verbose_name='Initialization date')), + ('hardware_brand', models.CharField(blank=True, max_length=190, null=True)), + ('hardware_model', models.CharField(blank=True, max_length=190, null=True)), + ('software_brand', models.CharField(blank=True, max_length=190, null=True)), + ('software_version', models.CharField(blank=True, max_length=190, null=True)), + ('limit_events', models.ManyToManyField(blank=True, to='pretixbase.Event', verbose_name='Limit to events')), + ('organizer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='pretixbase.Organizer')), + ], + ), + migrations.AlterUniqueTogether( + name='device', + unique_together={('organizer', 'device_id')}, + ), + ] diff --git a/src/pretix/base/models/__init__.py b/src/pretix/base/models/__init__.py index d483000373..b3614d5d32 100644 --- a/src/pretix/base/models/__init__.py +++ b/src/pretix/base/models/__init__.py @@ -2,6 +2,7 @@ from ..settings import GlobalSettingsObject_SettingsStore from .auth import U2FDevice, User from .base import CachedFile, LoggedModel, cachedfile_name from .checkin import Checkin, CheckinList +from .devices import Device from .event import ( Event, Event_SettingsStore, EventLock, EventMetaProperty, EventMetaValue, RequiredAction, SubEvent, SubEventMetaValue, generate_invite_token, diff --git a/src/pretix/base/models/devices.py b/src/pretix/base/models/devices.py new file mode 100644 index 0000000000..f92fdbe91b --- /dev/null +++ b/src/pretix/base/models/devices.py @@ -0,0 +1,82 @@ +import string + +from django.db import models +from django.db.models import Max +from django.utils.crypto import get_random_string +from django.utils.translation import ugettext_lazy as _ + + +def generate_serial(): + serial = get_random_string(allowed_chars='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', length=16) + while Device.objects.filter(unique_serial=serial).exists(): + serial = get_random_string(allowed_chars='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', length=16) + return serial + + +def generate_initialization_token(): + token = get_random_string(length=16, allowed_chars=string.ascii_lowercase + string.digits) + while Device.objects.filter(initialization_token=token).exists(): + token = get_random_string(length=16, allowed_chars=string.ascii_lowercase + string.digits) + return token + + +def generate_api_token(): + token = get_random_string(length=64, allowed_chars=string.ascii_lowercase + string.digits) + while Device.objects.filter(initialization_token=token).exists(): + token = get_random_string(length=64, allowed_chars=string.ascii_lowercase + string.digits) + return token + + +class Device(models.Model): + organizer = models.ForeignKey( + 'pretixbase.Organizer', + on_delete=models.PROTECT, + related_name='devices' + ) + device_id = models.PositiveIntegerField() + unique_serial = models.CharField(max_length=190, default=generate_serial, unique=True) + initialization_token = models.CharField(max_length=190, default=generate_initialization_token, unique=True) + api_token = models.CharField(max_length=190, unique=True, null=True) + all_events = models.BooleanField(default=False, verbose_name=_("All events (including newly created ones)")) + limit_events = models.ManyToManyField('Event', verbose_name=_("Limit to events"), blank=True) + name = models.CharField( + max_length=190, + verbose_name=_('Name') + ) + created = models.DateTimeField( + auto_now_add=True, + verbose_name=_('Setup date') + ) + initialized = models.DateTimeField( + verbose_name=_('Initialization date'), + null=True, + ) + hardware_brand = models.CharField( + max_length=190, + null=True, blank=True + ) + hardware_model = models.CharField( + max_length=190, + null=True, blank=True + ) + software_brand = models.CharField( + max_length=190, + null=True, blank=True + ) + software_version = models.CharField( + max_length=190, + null=True, blank=True + ) + + class Meta: + unique_together = (('organizer', 'device_id'),) + + def __str__(self): + return '#{} ({} {})'.format( + self.device_id, self.hardware_brand, self.hardware_model + ) + + def save(self, *args, **kwargs): + if not self.device_id: + self.device_id = (self.organizer.devices.aggregate(m=Max('device_id'))['m'] or 0) + 1 + super().save(*args, **kwargs)