class ResponseTemplateSerializer(DynamicFieldsMixin, RevalidateMixin, HyperlinkedMixin, ModelSerializer): hyperlinks = ( ('self', 'response-templates-detail', ( 'instance.name', 'name', )), ('rename', 'response-templates-rename', ( 'instance.name', 'name', )), ) name = LowercaseCharField(validators=[ UniqueValidator(queryset=ResponseTemplate.objects.all()), DjangoValidator() ]) context = JSONField(default={}, validators=[validate_template_context]) content = serializers.CharField(validators=[Jinja2TemplateValidator()]) content_type = serializers.CharField(validators=[RegexValidator( regex=re.compile(r'^([a-z]+)\/([a-z0-9+-\.]+)*$', re.IGNORECASE), message='Not a valid content_type.')], ) class Meta: fields = ('name', 'content', 'content_type', 'context', 'description') model = ResponseTemplate
class Migration(migrations.Migration): dependencies = [ ('hosting', '0002_hosting_domains'), ] operations = [ migrations.RenameField(model_name='hosting', old_name='label', new_name='name'), migrations.RunPython(fill_hosting_names), migrations.AlterField( model_name='hosting', name='name', field=LowercaseCharField(max_length=253), ), migrations.AlterField( model_name='hosting', name='_is_live', field=LiveField(default=True), ), migrations.AlterUniqueTogether( name='hosting', unique_together=set([('name', '_is_live')]), ), ]
class Coupon(models.Model): """Coupon describes possible discount. It's defined by unique name and should have either information about percent_off or amount_off. Currently only supported currency is USD. Coupon can be used for more than one month - by setting duration accordingly. Coupon can also expire and should generate discounts after expiration date which is specified by `redeem_by` field. """ CURRENCY_CHOICES = (('usd', 'USD'), ) name = models.CharField(max_length=32, unique=True, primary_key=True) percent_off = models.SmallIntegerField(null=True) amount_off = models.FloatField(null=True) currency = LowercaseCharField(max_length=3, choices=CURRENCY_CHOICES, default='usd') duration = models.SmallIntegerField(default=1) # in months redeem_by = models.DateField() class Meta: ordering = ('name', ) def redeem(self, instance, customer, save=True): """Use coupon generating a discount from it""" start = timezone.now().date() end = start + relativedelta(months=self.duration) discount = Discount(instance=instance, coupon=self, start=start, end=end, customer=customer) discount.full_clean() if save: discount.save() return discount def __str__(self): return 'Coupon[name=%s]' % self.name
class User(AclAbstractBaseModel, CacheableAbstractModel, LiveAbstractModel, TrackChangesAbstractModel, UniqueKeyAbstractModel): # v1 permission fields PERMISSION_CONFIG = { 'api_key': {API_PERMISSIONS.READ, API_PERMISSIONS.UPDATE}, 'admin': { 'write': FULL_PERMISSIONS, 'read': {API_PERMISSIONS.READ}, } } # v2 permission config WRITE_PERMISSION = Permission('write', actions=('update', 'partial_update', 'destroy', 'reset_key')) OBJECT_ACL_PERMISSIONS = ( DataObject.READ_PERMISSION, WRITE_PERMISSION, ) UPDATE_PERMISSION = Permission('update', actions=('update', 'partial_update', 'reset_key')) ENDPOINT_ACL_PERMISSIONS = ( DataObject.GET_PERMISSION, DataObject.LIST_PERMISSION, DataObject.CREATE_PERMISSION, UPDATE_PERMISSION, DataObject.DELETE_PERMISSION, ) KEY_FIELD_KWARGS = {} username = LowercaseCharField(max_length=64, db_index=True) password = models.CharField(max_length=128) created_at = models.DateTimeField(auto_now_add=True, db_index=True) groups = models.ManyToManyField('Group', through='Membership') class Meta: ordering = ('id', ) unique_together = ('username', '_is_live') def __init__(self, *args, **kwargs): self.profile_data = kwargs.pop('profile_data', None) super().__init__(*args, **kwargs) def __str__(self): return 'User[id=%s, username=%s]' % (self.id, self.username) def generate_key(self): return generate_key(parity=True) def set_password(self, raw_password): self.password = make_password(raw_password) def check_password(self, raw_password): """ Returns a boolean of whether the raw_password was correct. Handles hashing formats behind the scenes. """ def setter(raw_password): self.set_password(raw_password) self.save(update_fields=["password"]) return check_password(raw_password, self.password, setter) @staticmethod @cached() def get_group_ids_for_user(user_id): return list( Membership.objects.filter(user=user_id).values_list('group_id', flat=True)) def get_group_ids(self): return self.get_group_ids_for_user(self.id)
def add_key_field(sender, **kwargs): if issubclass(sender, UniqueKeyAbstractModel) and not sender._meta.proxy: field = LowercaseCharField(max_length=40, **sender.KEY_FIELD_KWARGS) field.contribute_to_class(sender, sender.KEY_FIELD_NAME)
class Hosting(LiveAbstractModel, DescriptionAbstractModel, CacheableAbstractModel, CreatedUpdatedAtAbstractModel, TrackChangesAbstractModel): PERMISSION_CONFIG = { 'admin': { 'full': FULL_PERMISSIONS, 'write': {API_PERMISSIONS.READ}, 'read': {API_PERMISSIONS.READ}, } } UPDATE_LOCK_KEY_TEMPLATE = 'lock:hosting:update:{instance.id}' class SSL_STATUSES(MetaIntEnum): CHECKING = -1, 'checking' OFF = 0, 'off' ON = 1, 'on' INVALID_DOMAIN = 2, 'invalid_domain' CNAME_NOT_SET = 3, 'cname_not_set' WRONG_CNAME = 4, 'wrong_cname' UNKNOWN = 5, 'unknown' name = LowercaseCharField(max_length=253) domains = ArrayField(base_field=models.CharField(max_length=253), default=[]) is_active = models.BooleanField(default=True) is_default = models.BooleanField(default=False) ssl_status = models.SmallIntegerField(choices=SSL_STATUSES.as_choices(), default=SSL_STATUSES.OFF.value) config = NullableJSONField(default={}) socket = models.ForeignKey('sockets.Socket', blank=True, null=True, default=None, on_delete=models.CASCADE) auth = HStoreField(default={}) _storage = None class Meta: ordering = ('id',) unique_together = ('name', '_is_live') verbose_name = 'Hosting' def __str__(self): return 'Hosting[id=%s, name=%s]' % (self.id, self.name) @classmethod def get_storage(cls): if cls._storage is None: cls._storage = DefaultStorage.create_storage( bucket_name=get_cur_loc_env('STORAGE_HOSTING_BUCKET'), storage_url=get_cur_loc_env('STORAGE_HOSTING_BUCKET_URL'), ) return cls._storage @classmethod def get_instance_lock_key(cls, instance): return cls.UPDATE_LOCK_KEY_TEMPLATE.format(instance=instance) @staticmethod @cached() def is_hosting_empty(hosting_id): return not HostingFile.objects.filter(hosting=hosting_id).exists() @classmethod def cnames_generator(cls, domains): return (d for d in domains if VALID_DOMAIN_REGEX.match(d)) @classmethod def find_cname(cls, domains): return next(cls.cnames_generator(domains), None) def get_cname(self): return Hosting.find_cname(self.domains) @property def is_empty(self): return Hosting.is_hosting_empty(self.id) @property def is_locked(self): return self.ssl_status == Hosting.SSL_STATUSES.CHECKING @property def is_browser_router_enabled(self): return self.config.get('browser_router', False) @classmethod def encrypt_passwd(cls, passwd): def salt(): symbols = ascii_letters + digits return choice(symbols) + choice(symbols) return 'crypt:{}'.format(crypt(passwd, salt())) def check_auth(self, uname, passwd): if uname in self.auth: _, encrypted_passwd = self.auth[uname].split(':', 1) return crypt(passwd, encrypted_passwd) == encrypted_passwd return False