class ProjectIdea(TimeStampedModel): title = models.CharField(_('Title'), max_length=255) description = models.TextField(_('Description')) slug = ShortUUIDField() user_votes = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='user_votes') created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="project_created_by") started_date = models.DateTimeField(blank=True, null=True) objects = models.Manager() hot_objects = HotIdeaManager() cold_objects = ColdIdeaManager() class Meta: ordering = ['-created'] def __str__(self): return '{0}'.format(self.title) @models.permalink def get_absolute_url(self): return ('projectidea-detail', [], {'slug': self.slug}) @property def started(self): if not self.started_date: return False else: return True
class Order(models.Model): cart = models.OneToOneField(Cart) number = models.CharField(max_length=64) date_created = models.DateField(auto_now_add=True) payment_proof = RestrictedFileField( blank=True, null=True, upload_to=upload_path, content_types=[ 'application/pdf', 'image/jpeg', 'image/gif', 'image/png' ], max_upload_size=5242880 # 5mb ) customer_name = models.CharField(max_length=64) phone_number = models.CharField(max_length=32) email = models.EmailField() shipping_address = models.TextField() message = models.TextField(blank=True) # we use a UUID here so that order URLs cannot # be guessed slug = ShortUUIDField() state = FSMField(default='open', protected=True) def save(self, *args, **kwargs): super(Order, self).save(*args, **kwargs) if not self.slug: self.slug = shortuuid.uuid() if not self.cart.checked_out: self.cart.checked_out = True if not self.number: self.number = str(str(self.id) + str(self.slug[:3])).upper() return super(Order, self).save(*args, **kwargs) # TODO change this, tightly coupled with VISA def get_absolute_url(self): return reverse_lazy('shop:order', kwargs={'slug': self.slug}) def payment_uploaded(self): return bool(self.payment_proof) @transition(field=state, source=['open', 'paid'], target='cancelled') def cancel(self, *args, **kwargs): return True @transition(field=state, source=['open', 'paid'], target='paid') def upload_payment(self, *args, **kwargs): return True @transition(field=state, source=['paid'], target='confirmed', conditions=[payment_uploaded]) def confirm(self, *args, **kwargs): return True @transition(field=state, source=['open', 'paid'], target='invalid') def invalidate(self, *args, **kwargs): return True
class Component(models.Model): id = ShortUUIDField(primary_key=True, editable=False) name = models.CharField(max_length=80) definition = models.CharField(max_length=255) wikipedia_link = models.CharField(max_length=255, blank=True) stack = models.ForeignKey('Stack', on_delete=models.CASCADE, related_name='components')
class TfeUser(AbstractUser): uuid = ShortUUIDField() def __str__(self): try: return f"{self.username}" except AttributeError: return ""
class Asset(TimeStamped): name = models.CharField(max_length=128) url = models.URLField() key = ShortUUIDField() publisher = models.ForeignKey('companies.Company', related_name='assets') def __unicode__(self): return '%s - %s' %(self.url, self.publisher.name)
class TechnologyNode(models.Model): id = ShortUUIDField(primary_key=True, editable=False) name = models.CharField(max_length=80) definition = models.CharField(max_length=255) wikipedia_link = models.CharField(max_length=255, blank=True) component = models.ForeignKey('Component', on_delete=models.SET_NULL, null=True, related_name='technologies')
class Visitor(TimeStamped): user = models.ForeignKey('users.User', blank=True, null=True) key = ShortUUIDField() has_opted_out = models.BooleanField(default=False) def set_opt_out_flag(self): self.has_opted_out = True self.save() def __unicode__(self): return self.key
class UserProfile(models.Model): uuid = ShortUUIDField() user = models.OneToOneField(TfeUser, on_delete=models.CASCADE) date_created = CreationDateTimeField() date_modified = ModificationDateTimeField() def __str__(self): try: return f"{self.user.username} Profile" except AttributeError: return ""
class Choice(TimeStampedModel): uuid = ShortUUIDField(db_index=True) question = models.ForeignKey(Question, related_name="choices") title = models.CharField(max_length=255) class Meta: ordering = ('-created', ) def __unicode__(self): return self.title
class BaseModel(models.Model): """ A Base Model Class """ slug = ShortUUIDField(blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) active = models.BooleanField(default=True) class Meta: abstract = True
class AutoLapseInstanceFile(models.Model): uuid = ShortUUIDField(db_index=True) created = models.DateTimeField(auto_now_add=True) instance = models.ForeignKey("AutoLapseInstance", related_name="autolapse_files") output_size = EnumIntegerField(AutoLapseOutputSizes) file_video_mp4 = models.FileField(upload_to=video_mp4_name_generator, max_length=512) file_video_webm = models.FileField(upload_to=video_webm_name_generator, max_length=512) file_video_gif = models.ImageField(upload_to=gif_name_generator, max_length=512)
class Default(models.Model): """ Model com campos padrão que serão herdados por todos os modelos subsequentes. Por ter o atributo Meta abstract=True ele não é adicionado ao banco de dados como tabela. O campo 'id' é a primary key por padrão dos modelos criados no banco de dados. O campo 'unique_id' é criado apenas por fins de não referenciar o id da linha diretamente caso necessário. """ unique_id = ShortUUIDField() created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) class Meta: abstract = True ordering = ['created']
class AutoLapseConfiguration(models.Model): uuid = ShortUUIDField(db_index=True) create_new_every = models.IntegerField( help_text="How many uploads until we automatically generate a lapse") source_gallery = models.ForeignKey("images.Gallery", related_name="autolapse_configs") image_count = models.IntegerField( help_text="How many images maximum to lapse") frames_per_second = models.IntegerField( help_text="FPS of the resulting video") enabled = models.BooleanField() max_output_size = EnumIntegerField(AutoLapseOutputSizes, help_text="Biggest size we generate")
class User(AbstractBaseUser, PermissionsMixin): """ Users within the Django authentication system are represented by this model. Email and password are required. Other fields are optional. """ uid = ShortUUIDField(help_text=_("The unique ID under which the" " user is to be accessed.")) email = models.EmailField(_('email address'), unique=True, max_length=254) first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=30, blank=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_('Designates whether the user can log into this admin ' 'site.')) is_active = models.BooleanField( _('active'), default=True, help_text=_('Designates whether this user should be treated as ' 'active. Unselect this instead of deleting accounts.')) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) objects = UserManager() USERNAME_FIELD = 'email' class Meta: verbose_name = _('user') verbose_name_plural = _('authentication') def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. """ full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): "Returns the short name for the user." return self.first_name def email_user(self, subject, message, from_email=None): """ Sends an email to this User. """ send_mail(subject, message, from_email, [self.email]) def __unicode__(self): return self.email
class UUIDBaseModel(DateLogMixin): # uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) uuid = ShortUUIDField(unique=True) class Meta: abstract = True ordering = ('-created_at', ) def __str__(self): return str(self.uuid) @property def short_id(self): return hashids.encode(int(self.uuid))
class Instance(models.Model): is_alive = models.BooleanField(default=False) uuid = ShortUUIDField(auto=True) last_beat = models.DateTimeField(null=True, blank=True) executor = models.ForeignKey("Executor", related_name="instances") class Meta: app_label = "core" db_table = "fastapp_instance" def mark_down(self): self.is_alive = False self.save() def __str__(self): return "Instance: %s" % (self.executor.base.name)
class BadgeInstance(TimeStampedModel): template = models.ForeignKey(BadgeTemplate, on_delete=models.CASCADE) data = JSONField(blank=True) key = ShortUUIDField() external = models.TextField(unique=True) def __str__(self): return self.external def save(self, *args, **kwargs): # TODO: check for _loaded_values # https://docs.djangoproject.com/en/2.2/ref/models/instances/#customizing-model-loading super().save(*args, **kwargs) def build_archive(self): pass
class ShortUUIDBase(models.Model): """Mixin to support models which have a slug which needs to be translatable into a guid. """ slug = ShortUUIDField(blank=False) class Meta: abstract = True @property def guid(self): """Returns the slug to a UUID.""" return decode(self.slug) @property def guid_str(self): """Returns the UUID as upperacse hexadecimal.""" return self.guid.hex.upper()
class AutoLapseInstance(models.Model): class Meta: get_latest_by = "created" created = models.DateTimeField(auto_now_add=True) uuid = ShortUUIDField(db_index=True) configuration = models.ForeignKey("AutoLapseConfiguration", related_name="autolapse_instances") status = EnumIntegerField(LapseInstanceStatus) @property def preview(self): return self.autolapse_files.filter(output_size=3).get() @property def default(self): return self.autolapse_files.filter(output_size=2).get()
class Node(MPTTModel): id = ShortUUIDField(primary_key=True, editable=False) name = models.CharField(max_length=255) path = models.TextField(null=True, blank=True) parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True) class MPTTMeta: """Insertion in the tree is ordered by name""" order_insertion_by = ['name'] class Meta: """ Unique constraint to prevent duplicate category in the same tree level """ unique_together = (('name', 'parent'), ) def __str__(self): return self.name def save(self, *args, **kwargs): """Override to call clean for manually created objects""" self.full_clean() super(Node, self).save(*args, **kwargs) @property def subcategories(self): """ Get all the subcategories of this node returns: queryset of subcategories that belong to this node """ return self.get_descendants(include_self=False) @property def subcategories_count(self): """ Get the number of subcategories in this node returns: count of subcategories that belongs to this node """ return self.get_descendant_count()
class Coupon(TimeStamped, ToCompany): code = ShortUUIDField() campaign = models.ForeignKey(Campaign, related_name='coupons') redeemed_on = models.DateTimeField(null=True, blank=True) claimed_on = models.DateTimeField(null=True, blank=True) value = models.DecimalField(default=1, max_digits=20, decimal_places=4) """ What is the difference between claimed on and redeemed_on? claimed_on = when the coupon is assigned a user, redeemed_on = when the coupon is verified by advertiser/desk clerk and discount is approved """ claimed_by = models.ForeignKey('users.User', blank=True, null=True) # overriding custom manager objects = CouponManager.from_queryset(CouponQuerySet)() def __unicode__(self): return 'Campaign: %s, Coupon: %s' % (self.campaign.name, self.code) def claim(self, user): """ sets the coupon to claimed, by setting the 'claimed_on' and 'claimed_by' properties. Sends the email after with coupon code to the end user Todo: the input parameter 'user' should be replaced with email, also, request must be part of this to get the desired customer. Params: user - must confine to apps.models.User object """ from django.utils import timezone from django.conf import settings self.claimed_on = timezone.now() self.claimed_by = user self.save() self.generate_barcode() subject = "[IntentAware] Your offer code for %s's campaign %s" % ( self.company.name, self.campaign.name) user.send_templated_email(template='emails/coupon-code.html', context={ 'coupon': self, 'STATIC_URL': settings.STATIC_URL, 'MEDIA_URL': settings.MEDIA_URL, }, subject=subject) def redeem(self): from django.utils import timezone as _tz """ now = _tz.now() delta = _tz.timedelta(hours=5) print now -self.claimed_on if (now - self.claimed_on) < delta: self.redeemed_on = now self.save() return self else: return self """ now = _tz.now() self.redeemed_on = now self.save() def generate_barcode(self): """ Generates the barcode image for the coupon """ from apps.common.utils.barcodes import BarcodeFromString BarcodeFromString(self.code)
class Vm(models.Model): id = ShortUUIDField(primary_key=True, unique=True, editable=False) platform = models.ForeignKey(Platform, on_delete=models.CASCADE) name = models.CharField(max_length=64) config = models.JSONField() state = models.JSONField() network = models.ForeignKey(Network, on_delete=models.CASCADE) template = models.ForeignKey(VmTemplate, on_delete=models.CASCADE) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) deleted = models.DateTimeField(default=None, null=True) def __str__(self): return self.name @property def fqdn(self): return "{}.{}".format(self.name, self.platform.config['domain']) @property def status(self): status = [] active_providers = self.platform.active_providers for key, state in self.state.items(): if 'status' in state: status.append(state['status']) if 'destroying' in status: return 'destroying' for provider in active_providers: if provider not in self.state: return 'provisioning' if 'provisioning' in status: return 'provisioning' if 'error' in status: return 'error' if 'provisioned' in status: return 'provisioned' return 'unknown' def get_pve_node_and_vm(self): if 'proxmox' not in self.state or 'id' not in self.state[ 'proxmox'] or self.state['proxmox']['id'] is None: return None, None pve_vm = None pve_node = None for t in self.platform.proxmox().cluster.resources.get(type='vm'): if t['type'] == 'qemu' and int(t['vmid']) == int( self.state['proxmox']['id']): pve_node = self.platform.proxmox().nodes(t['node']) pve_vm = pve_node.qemu(self.state['proxmox']['id']) self.state['proxmox']['node'] = t['node'] return pve_node, pve_vm return None, None def update_state(self): self.update_netbox() self.update_powerdns() self.update_freeipa() self.update_awx() self.update_proxmox() self.update_monitoring() def update_netbox(self): vm = None if 'netbox' not in self.state: self.state['netbox'] = {} vm = self.platform.netbox().virtualization.virtual_machines.create( name=self.name, site=self.platform.site_id, cluster=self.platform.cluster_id, role=self.config['role'], vcpus=self.config['hw']['cpu_cores'], memory=int(self.config['hw']['memory']) * 1024, disk=int(self.config['hw']['os_disk']), status='active') self.state['netbox']['id'] = vm.id self.save() if vm is None: vm = self.platform.netbox().virtualization.virtual_machines.get( self.state['netbox']['id']) if self.platform.netbox().virtualization.interfaces.get( virtual_machine_id=vm.id, name="eth0") is None: interface = self.platform.netbox( ).virtualization.interfaces.create(virtual_machine=vm.id, name='eth0') ipv4 = self.platform.netbox().ipam.ip_addresses.create( assigned_object_type="virtualization.vminterface", assigned_object_id=interface['id'], address="{}/{}".format( self.config['net']['ipv4']['ip'], self.config['net']['ipv4']['prefixlen']), status="active") ipv6 = self.platform.netbox().ipam.ip_addresses.create( assigned_object_type="virtualization.vminterface", assigned_object_id=interface['id'], address="{}/{}".format( self.config['net']['ipv6']['ip'], self.config['net']['ipv6']['prefixlen']), status="active") vm.primary_ip4 = ipv4['id'] vm.primary_ip6 = ipv6['id'] vm.save() if 'interface' not in self.state['netbox']: self.state['netbox']['interface'] = [] self.state['netbox']['interface'].append({ 'id': interface['id'], 'name': interface['name'] }) if 'ip_addresses' not in self.state['netbox']: self.state['netbox']['ip_addresses'] = [] self.state['netbox']['ip_addresses'].append({ 'id': ipv4['id'], 'address': ipv4['address'], 'interface_id': ipv4['assigned_object_id'] }) self.state['netbox']['ip_addresses'].append({ 'id': ipv6['id'], 'address': ipv6['address'], 'interface_id': ipv6['assigned_object_id'] }) self.state['netbox']['status'] = "provisioned" self.save() return self.state['netbox'] def update_proxmox(self): proxmox = self.platform.proxmox() if 'proxmox' not in self.state: self.state['proxmox'] = {} self.save() # Get the first proxmox node - TODO Add option to pass node in create request for key, value in self.platform.config['proxmox']['nodes'].items(): pve_node_name = key break from vm.proxmox import create_qemu_vm_job create_qemu_vm_job.delay(self.pk, pve_node_name) if 'proxmox' in self.state and 'id' in self.state[ 'proxmox'] and self.state['proxmox']['id'] is not None: pve_node, pve_vm = self.get_pve_node_and_vm() if pve_vm is not None: status = pve_vm.status().current.get() config = pve_vm.config().get() self.state['proxmox']['name'] = status['name'] self.state['proxmox']['vm_status'] = status['status'] self.state['proxmox']['config'] = config self.save() return self.state['proxmox'] def update_powerdns(self): fqdn = "{}.{}.".format(self.name, self.platform.config['domain']) if 'powerdns' not in self.state: rrsets = [] rrsets.append({ "name": fqdn, "changetype": "replace", "type": "A", "records": [{ "content": self.config['net']['ipv4']['ip'], "disabled": False, "type": "A" }], "ttl": 900 }) rrsets.append({ "name": fqdn, "changetype": "replace", "type": "AAAA", "records": [{ "content": self.config['net']['ipv6']['ip'], "disabled": False, "type": "AAAA" }], "ttl": 900 }) print(self.platform.powerdns().set_records( self.platform.config['domain'] + ".", rrsets)) self.state['powerdns'] = {} self.state['powerdns']['domains'] = {} self.state['powerdns']['domains'][self.platform.config['domain'] + "."] = rrsets self.save() # Hack to support custom in-addr.arpa zones. # Example zone 64-127.182.80.185.in-addr.arpa (for a network smaller then /24) # Assumes that this will never be used on bigger networks than /24 if 'v4_rdns_zone' in self.network.config: p = re.compile('(.*)\.(.*)\.(.*)\.(.*)') m = p.match(self.config['net']['ipv4']['ip']) rdns_v4_zone = self.network.config['v4_rdns_zone'] v4_ptr = "{0}.{1}".format(m.group(4), rdns_v4_zone) else: rdns_v4_zones = self.platform.powerdns().search( "*.in-addr.arpa", 2000, "zone") v4_ptr = ipaddress.IPv4Address( self.config['net']['ipv4']['ip']).reverse_pointer rdns_v4_zone = None for zone in [sub['name'] for sub in rdns_v4_zones]: test = str(v4_ptr).split('.') for i in range(len(test) - 2): x = len(test) - i if ".".join(test[-x:]) + '.' in zone: rdns_v4_zone = zone break rdns_v6_zones = self.platform.powerdns().search( "*.ip6.arpa", 2000, "zone") v6_ptr = ipaddress.IPv6Address( self.config['net']['ipv6']['ip']).reverse_pointer rdns_v6_zone = None for zone in [sub['name'] for sub in rdns_v6_zones]: test = str(v6_ptr).split('.') for i in range(len(test) - 2): x = len(test) - i if ".".join(test[-x:]) + '.' in zone: rdns_v6_zone = zone break if rdns_v4_zone is not None: rrsets = [] rrsets.append({ "name": v4_ptr + '.', "changetype": "replace", "type": "PTR", "records": [{ "content": fqdn, "disabled": False, "type": "PTR" }], "ttl": 900 }) print(rdns_v4_zone) print(rrsets) print(self.platform.powerdns().set_records( rdns_v4_zone, rrsets)) self.state['powerdns']['domains'][rdns_v4_zone] = rrsets self.save() if rdns_v6_zone is not None: rrsets = [] rrsets.append({ "name": v6_ptr + '.', "changetype": "replace", "type": "PTR", "records": [{ "content": fqdn, "disabled": False, "type": "PTR" }], "ttl": 900 }) print(rdns_v6_zone) print(rrsets) print(self.platform.powerdns().set_records( rdns_v6_zone, rrsets)) self.state['powerdns']['domains'][rdns_v6_zone] = rrsets self.save() self.state['powerdns']['status'] = "provisioned" return self.state['powerdns'] def update_freeipa(self): if 'freeipa' not in self.platform.config: return False fqdn = "{}.{}".format(self.name, self.platform.config['domain']) if 'freeipa' not in self.state: client = self.platform.freeipa() print( client.host_add(fqdn, o_ip_address=self.config['net']['ipv4']['ip'])) self.state['freeipa'] = { "fqdn": fqdn, "status": "provisioned", "hostgroups": [] } if 'default_hostgroups' in self.platform.config['freeipa']: for hostgroup in self.platform.config['freeipa'][ 'default_hostgroups']: client.hostgroup_add_member(hostgroup, o_host=fqdn) self.state['freeipa']['hostgroups'].append(hostgroup) self.save() return self.state['freeipa'] def update_awx(self): if 'awx' not in self.platform.config: return False fqdn = "{}.{}".format(self.name, self.platform.config['domain']) if 'awx' not in self.state: client = self.platform.awx() client.create_host_in_inventory( inventory=self.platform.config['awx']['inventory'], name=fqdn, description="orc_managed", organization=self.platform.config['awx']['organization']) self.state['awx'] = { "fqdn": fqdn, "inventory": self.platform.config['awx']['inventory'] } self.state['awx']['status'] = "provisioned" self.save() if 'awx_templates' not in self.state: self.state['awx_templates'] = {} self.save() if 'awx_templates' in self.config: for key, template in self.config['awx_templates'].items(): if key not in self.state['awx_templates']: self.state['awx_templates'][key] = {"status": "new"} self.save() if key in self.state['awx_templates'] and self.state[ 'awx_templates'][key]["status"] in [ "successful", "provisioned", "provisioning", "pending", "failed" ]: continue requirements_met = True if 'trigger' in template: if 'after_state' in template['trigger']: for t in template['trigger']['after_state']: if t not in self.state or self.state[t][ "status"] not in ["provisioned"]: requirements_met = False if requirements_met: self.state['awx_templates'][key] = { "status": "provisioning" } from vm.jobs import run_awx_template_job run_awx_template_job.delay(self.pk, template['id'], key) break else: self.state['awx_templates'][key] = { "status": "missing_dependency" } return self.state['awx'] def update_monitoring(self): # TODO Generate prometheus job that will generate files for ICMP monitoring pass def delete_vm(self): self.delete_from_proxmox() self.delete_from_freeipa() self.delete_from_awx() self.delete_from_powerdns() # Only delete host from netbox and orc after host is removed from Proxmox if 'proxmox' not in self.state: self.delete_from_netbox() self.delete() def delete_from_netbox(self): if 'netbox' not in self.state or 'id' not in self.state['netbox']: return False vm = self.platform.netbox().virtualization.virtual_machines.get( self.state['netbox']['id']) vm.delete() del self.state['netbox'] self.save() return True def delete_from_proxmox(self): proxmox = self.platform.proxmox() if 'proxmox' not in self.state or 'id' not in self.state[ 'proxmox'] or self.state['proxmox']['id'] is None: if 'proxmox' in self.state: del self.state['proxmox'] return False self.state['proxmox']['status'] = "destroying" self.save() from vm.proxmox import delete_qemu_vm_job delete_qemu_vm_job.delay(self.pk) return True def delete_from_powerdns(self): if 'powerdns' not in self.state or 'domains' not in self.state[ 'powerdns']: return False for domain in list(self.state['powerdns']['domains']): rrsets = [] for rrset in self.state['powerdns']['domains'][domain]: rrset['changetype'] = "delete" rrsets.append(rrset) print(self.platform.powerdns().set_records(domain, rrsets)) del self.state['powerdns']['domains'][domain] self.save() del self.state['powerdns'] self.save() return True def delete_from_freeipa(self): if 'freeipa' not in self.state or 'fqdn' not in self.state['freeipa']: return False print(self.platform.freeipa().host_del(self.state['freeipa']['fqdn'])) del self.state['freeipa'] self.save() return True def delete_from_awx(self): if 'awx' not in self.state or 'fqdn' not in self.state[ 'awx'] or 'inventory' not in self.state['awx']: return False client = self.platform.awx() client.delete_inventory_host( inventory=self.state['awx']['inventory'], name=self.state['awx']['fqdn'], organization=self.platform.config['awx']['organization']) del self.state['awx'] del self.state['awx_templates'] self.save() return True
class Gallery(models.Model): user = models.ForeignKey(User, related_name="galleries") updated = models.DateTimeField(auto_now=True) # other fields uuid = ShortUUIDField(db_index=True) # info fields rel_start = models.DateField(null=True, blank=True, verbose_name="Time Period Start") rel_end = models.DateField(null=True, blank=True, verbose_name="Time Period End") title = models.CharField(max_length=256, null=True, blank=True) # status fields private = models.BooleanField(default=True) # deletable deletable = models.BooleanField(default=True) # let the user pick how many cards to show in a gallery. @property def display_card_class(self): return [ self.DisplaySize.TINY, self.DisplaySize.SMALL, self.DisplaySize.MEDIUM, self.DisplaySize.LARGE ] @property def display_lapse_class(self): return [self.DisplaySize.LAPSE_SM, self.DisplaySize.LAPSE_LG] class DisplaySort(Enum): UPLOADED_ASC = 0 UPLOADED_DSC = 1 EXIF_ASC = 2 EXIF_DSC = 3 class Labels: UPLOADED_ASC = "Oldest Uploaded First" UPLOADED_DSC = "Newest Uploaded First" EXIF_ASC = "Taken First" EXIF_DSC = "Taken Last" class DisplaySize(Enum): TINY = 0 SMALL = 1 MEDIUM = 2 LARGE = 3 LAPSE_SM = 4 LAPSE_LG = 5 class Labels: TINY = "Twelve Images Per Row" SMALL = "Six Images Per Row" MEDIUM = "Three Images Per Row" LARGE = "Two Images Per Row" LAPSE_SM = "Ultra Compact Lapse Layout" LAPSE_LG = "Less Compact Lapse Layout" display_density = EnumIntegerField(DisplaySize, default=2) display_sort = EnumIntegerField(DisplaySort, default=0) def __unicode__(self): return self.title def __str__(self): return self.title objects = GalleryManager() class Meta: unique_together = ('user', 'title') @property def has_images(self): return self.images.exists() @property def rand_img(self): return self.images.order_by("?")[0] @property def gallery_pagination_count(self): if self.display_density == Gallery.DisplaySize.TINY: return 36 elif self.display_density == Gallery.DisplaySize.SMALL: return 24 elif self.display_density == Gallery.DisplaySize.MEDIUM: return 12 elif self.display_density == Gallery.DisplaySize.LARGE: return 16 elif self.display_density == Gallery.DisplaySize.LAPSE_LG: return 25 * 8 elif self.display_density == Gallery.DisplaySize.LAPSE_SM: return 29 * 15 @property def template_display_class(self): if self.display_density == Gallery.DisplaySize.TINY: return "s1 m1" elif self.display_density == Gallery.DisplaySize.SMALL: return "s2 m2" elif self.display_density == Gallery.DisplaySize.MEDIUM: return "s4 m4" elif self.display_density == Gallery.DisplaySize.LARGE: return "s6 m6" elif self.display_density == Gallery.DisplaySize.LAPSE_LG: return "60px" elif self.display_density == Gallery.DisplaySize.LAPSE_SM: return "40px" @property def template_divisibility(self): if self.display_density == Gallery.DisplaySize.TINY: return 12 elif self.display_density == Gallery.DisplaySize.SMALL: return 6 elif self.display_density == Gallery.DisplaySize.MEDIUM: return 3 elif self.display_density == Gallery.DisplaySize.LARGE: return 2 @property def display_sort_string(self): if self.display_sort == Gallery.DisplaySort.UPLOADED_ASC: return ["uploaded"] elif self.display_sort == Gallery.DisplaySort.UPLOADED_DSC: return ["-uploaded"] elif self.display_sort == Gallery.DisplaySort.EXIF_ASC: return ["exif_timestamp"] elif self.display_sort == Gallery.DisplaySort.EXIF_DSC: return ["-exif_timestamp"] @property def latest_lapses_exist(self): configs = self.autolapse_configs.all() return any([c.autolapse_instances.exists() for c in configs]) @property def latest_lapse_instances_for_preview(self): # print "xyz" configs = self.autolapse_configs.all() inst = {} for c in configs: if c.autolapse_instances.exists(): inst[c.uuid] = c.autolapse_instances.filter().latest() else: inst[c.uuid] = "" return inst
class Stack(models.Model): id = ShortUUIDField(primary_key=True, editable=False) name = models.CharField(max_length=80) definition = models.CharField(max_length=255) wikipedia_link = models.CharField(max_length=255, blank=True)
class Term(models.Model): id = ShortUUIDField(primary_key=True, editable=False) name = models.CharField(max_length=80) definition = models.TextField()
class Image(models.Model): user = models.ForeignKey(User) gallery = models.ForeignKey(Gallery, related_name="images") uploaded = models.DateTimeField(auto_now_add=True) title = models.CharField(max_length=256, null=True, blank=True) tags = TaggableManager(blank=True) uuid = ShortUUIDField(db_index=True) original = models.ImageField(upload_to=set_image_name_on_upload, ) _view_mapping = { "view.3d.180": "view_3d_180", "view.3d": "view_3d_360", "view.3d.360": "view_3d_360", "view.3d.sphere": "view_3d_360", "view.sphere": "view_3d_360", "view.pano": "view_2d_pano", "view.pan": "view_2d_pano", "view.panorama": "view_2d_pano", "view.panoramic": "view_2d_pano", } view_flags = BitField(flags=( ('view_3d_180', '180 Degrees 3D'), ('view_3d_360', '360 Degrees 3D'), ('view_2d_pano', 'Panoramic'), ), null=True) # for multiple tags we use the first view_default = models.CharField(max_length=32, null=True, blank=True) def self_uuid(self): return self.uuid full_fixed = ImageSpecField( source="original", processors=[Transpose()], format="JPEG", ) bigger = ImageSpecField( source="full_fixed", processors=[ResizeToCover(1440, 1080, upscale=False)], format="JPEG", options={ 'quality': 80, 'prefix': "b" }) default = ImageSpecField( source="full_fixed", processors=[ResizeToCover(720, 540, upscale=False)], format="JPEG", options={ 'quality': 80, 'prefix': "d" }) preview = ImageSpecField(source="full_fixed", processors=[SmartResize(320, 240)], format="JPEG", options={ 'quality': 80, 'prefix': "p" }) thumb = ImageSpecField( source="full_fixed", processors=[SmartResize(160, 120)], format="JPEG", options={ 'quality': 60, 'prefix': "t" }, ) tiny_thumb = ImageSpecField( source="full_fixed", processors=[SmartResize(80, 60)], format="JPEG", options={ 'quality': 40, 'prefix': "tt" }, ) AVAIL_SIZES = [ "full_fixed", "bigger", "default", "preview", "thumb", "tiny_thumb" ] AVAIL_INTS = [0, 1, 2, 3, 4, 5] exif_data = models.ManyToManyField("EXIFEntry", blank=True) exif_timestamp = models.DateTimeField(null=True, blank=True) @property def uuid_as_b64(self): return base64.b64encode(self.uuid) def query_exif(self, only_when_empty=True, do_empty=False): image = IMG.open(self.original) if do_empty: self.exif_data.clear() if only_when_empty: do = not self.exif_data.exists() else: do = True if do: try: exif_raw = image._getexif() except: # no usable exif return # I guess this deals with the compactness, so it needs to be decoded? if exif_raw: exif_decoded = { TAGS.get(k): v for k, v in exif_raw.iteritems() } out = [] for key, value in exif_decoded.iteritems(): ek, ck = ExifKey.objects.get_or_create(key=key) ev, cv = ExifValue.objects.get_or_create(value=value) ee, ce = EXIFEntry.objects.get_or_create(key=ek, value=ev) self.exif_data.add(ee) if key == "DateTime": value_stf = datetime.strptime(value, "%Y:%m:%d %H:%M:%S") self.exif_timestamp = value_stf self.save() else: pass # no exif def cached_full_fixed(self): generator = ImageCacheFile(self.full_fixed) return generator.generate() def cached_bigger(self): generator = ImageCacheFile(self.bigger) return generator.generate() def cached_default(self): generator = ImageCacheFile(self.default) return generator.generate() def cached_preview(self): generator = ImageCacheFile(self.preview) return generator.generate() def cached_thumb(self): generator = ImageCacheFile(self.thumb) return generator.generate() def cached_tiny_thumb(self): generator = ImageCacheFile(self.tiny_thumb) return generator.generate() def get_next_by_gallery_ordering(self): gallery = self.gallery gallery_sort = gallery.display_sort_string if gallery_sort == ['uploaded']: try: return self.get_next_by_uploaded(gallery=gallery) except: return None if gallery_sort == ['-uploaded']: try: return self.get_previous_by_uploaded(gallery=gallery) except: return None # todo add EXIF based sorting def get_prev_by_gallery_ordering(self): gallery = self.gallery gallery_sort = gallery.display_sort_string if gallery_sort == ['uploaded']: try: return self.get_previous_by_uploaded(gallery=gallery) except: return None if gallery_sort == ['-uploaded']: try: return self.get_next_by_uploaded(gallery=gallery) except: return None
class Auction(DeletableTimeStampedModel): STATUS_LIVE = 1 STATUS_FINISHED_SOLD = 2 STATUS_FINISHED_UNSOLD = 3 _STATUS_CHOICES = ( (STATUS_LIVE, 'Live'), (STATUS_FINISHED_SOLD, 'Finished Sold'), (STATUS_FINISHED_UNSOLD, 'Finished Unsold'), ) status = models.IntegerField(choices=_STATUS_CHOICES, default=STATUS_LIVE) experience = models.ForeignKey( Experience, related_name='auctions', help_text='The experience this auction was created from') title = models.CharField( max_length=255, help_text='Title of the experience being auctioned') description = models.TextField( help_text='Description of the experience being auctioned') location = models.CharField(max_length=255, help_text='Location name of the experience') coords = models.PointField( help_text='Location coordinates of the experience') terms = models.TextField( null=True, blank=True, help_text='Terms and conditions for the auction/experience') pax_adults = models.PositiveSmallIntegerField( default=2, help_text='Number of adults accepted as part of the experience') pax_children = models.PositiveSmallIntegerField( default=0, help_text='Number of children accepted as part of the experience') currency = models.ForeignKey( Currency, default=settings.DEFAULT_CURRENCY_ID, help_text='The date and time the experience starts') url = models.URLField( null=True, blank=True, help_text='View the experience on the providers website') check_in = models.DateTimeField( help_text='The date and time the experience starts') check_out = models.DateTimeField( help_text='The date and time the experience ends') starting_price = models.DecimalField( max_digits=10, decimal_places=2, help_text='The initial price for the auction when it goes live') reserve_price = models.DecimalField( max_digits=10, decimal_places=2, help_text='The minimum price that will be accpeted to win this auction' ) end_date = models.DateTimeField( help_text='The date and time the auction finishes') view_count = models.PositiveIntegerField( default=0, help_text='The number of times auction details have been viewed') search_appearance_count = models.PositiveIntegerField( default=0, help_text='The number of times this auction has ' 'appeared in search results or on the homepage') featured = models.BooleanField( default=False, help_text='Set to true to show this auction in ' 'the featured section on the homepage') uuid = ShortUUIDField() objects = AuctionManager() def __unicode__(self): return '{}, {}, ending {}'.format(self.title, self.formatted_current_price(), self.end_date) def get_absolute_url(self): return self.get_guest_absolute_url() def get_provider_absolute_url(self): return reverse('auctions:provider-auction', args=(self.id, )) def get_guest_absolute_url(self): return reverse('auctions:public-auction', args=(self.id, )) def get_guest_confirmation_url(self): return '{}#confirm-{}'.format(reverse('auctions:won-auctions'), self.id) def is_live(self): """ Return whether the auction is still biddable """ return self.end_date > datetime.utcnow().replace(tzinfo=pytz.utc) def is_finished(self): """ Return whether the auction is still biddable """ return self.end_date <= datetime.utcnow().replace(tzinfo=pytz.utc) def was_won(self): return self.is_finished() and self.current_price() > self.reserve_price def highest_bid(self): if self.bids.count() > 0: return self.bids.order_by('-price').first() return None def current_price(self): bid = self.highest_bid() if bid is not None: return bid.price return self.starting_price def formatted_current_price(self): return '{}{}'.format(self.currency.symbol, self.current_price()) def formatted_reserve_price(self): return '{}{}'.format(self.currency.symbol, self.reserve_price) def formatted_starting_price(self): return '{}{}'.format(self.currency.symbol, self.starting_price) def get_default_image(self): if self.images.filter(default=True).exists(): return self.images.filter(default=True).first() return self.images.first() def total_pax(self): return self.pax_adults + self.pax_children @property def provider_websocket_group(self): """ Return the channel name that a provider should subscribe to when viewing a live auction. :return: """ return Group('provider-auction-{}'.format(self.id)) def send_provider_message(self, message): self.provider_websocket_group.send(message) @property def public_websocket_group(self): """ Return the channel name that a provider should subscribe to when viewing a live public auction. :return: """ return Group('public-auction-{}'.format(self.id)) def send_public_message(self, message): self.public_websocket_group.send(message) def mark_complete(self): from auction_rooms.auctions.signals import auction_completed if self.bids.count() == 0 or self.current_price() < self.reserve_price: # Auction did not sell self.status = self.STATUS_FINISHED_UNSOLD else: # Auction sold self.status = self.STATUS_FINISHED_SOLD self.save() auction_completed.send(sender=self.__class__, auction=self) def is_ending(self): now = datetime.utcnow().replace(tzinfo=pytz.utc) return self.is_live() and self.end_date < now + timedelta(hours=24) def pretty_checkin_date(self): return self.check_in.strftime('%a, %-d %b %Y ') def pretty_checkin(self): return self.check_in.strftime('%H:%M %a, %-d %b %Y ') def pretty_checkout_date(self): return self.check_out.strftime('%a, %-d %b %Y ') def pretty_checkout(self, include_time=True): return self.check_out.strftime('%H:%M %a, %-d %b %Y ') def pretty_duration(self): days = (self.check_out.date() - self.check_in.date()).days return '{} Night{}'.format(days, 's' if days > 1 else '') def is_selling(self): """ Return true if the auction has met the reserve price :return: """ return self.current_price() >= self.reserve_price def related_auctions(self): """ Returns any other live auctions for the same experience :return: """ return Auction.objects.live().filter( experience=self.experience).exclude( pk=self.id).order_by('end_date') def local_auctions(self): """ Returns any any local auctions in a 50 mile radius :return: """ return Auction.objects.live().filter( coords__distance_lte=(self.coords, D(mi=50))).exclude( experience=self.experience).annotate( distance=Distance('coords', self.coords)).order_by( 'distance', 'end_date')
class ShortUUIDTestModel_field(models.Model): a = models.IntegerField() uuid_field = ShortUUIDField() class Meta: app_label = 'django_extensions'
class User(AbstractBaseUser, PermissionsMixin): GENDER_CHOICES = (('Male', 'Male'), ('Female', 'Female')) first_name = models.CharField(_('first name'), max_length=255) last_name = models.CharField(_('last name'), max_length=255) slug = ShortUUIDField() email = models.EmailField(_('email'), unique=True) phone = models.CharField(_('phone'), max_length=100, blank=True, null=True) forget_password_link = models.CharField(_('forget_password_link'), max_length=200, blank=True, null=True, unique=True) forget_password_status = models.BooleanField(default=False) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_('Designates whether the user can log into this admin ' 'site.')) created = models.DateTimeField(_('created'), blank=True, editable=False, default=timezone.now) modified = models.DateTimeField(_('modified'), auto_now=True) is_active = models.BooleanField(_('is active'), default=True) # profile details profile_image = models.ImageField(blank=True, null=True, upload_to=user_profile_image) date_of_birth = models.DateField(blank=True, null=True) gender = models.CharField(max_length=255, blank=True, null=True, choices=GENDER_CHOICES) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] def __str__(self): return '{}'.format(self.get_full_name() if self.get_full_name( ) else self.email.split('@')[0]) def get_full_name(self): "Returns the first_name plus the last_name, with a space in between." full_name = u'%s %s' % (self.first_name, self.last_name) return full_name.capitalize().strip() def get_short_name(self): return self.get_full_name() if self.get_full_name( ) else self.email.split('@')[0] @classmethod def create_user(cls, first_name, last_name, email, password, gender): cls.objects.create_user(email, password, first_name=first_name, last_name=last_name, gender=gender)
class ShortUUIDTestModel_pk(models.Model): uuid_field = ShortUUIDField(primary_key=True) class Meta: app_label = 'django_extensions'
def get_uid(self): if self.is_new(): pf = ShortUUIDField() self.uid = self.uid_prefix + '_' + pf.create_uuid() return self.uid