class Commentable(models.Model): """ Mixin for models which can be commented. """ n_comments = models.IntegerField(verbose_name=_('number of comments'), blank=True, default=0, editable=False) commenting = EnumIntegerField(Commenting, verbose_name=_('commenting'), default=Commenting.NONE) voting = EnumIntegerField(Commenting, verbose_name=_('voting'), default=Commenting.REGISTERED) def recache_n_comments(self): new_n_comments = self.comments.count() if new_n_comments != self.n_comments: self.n_comments = new_n_comments self.save(update_fields=("n_comments",)) # if commentable has a parent hearing, recache the hearing comment count if hasattr(self, 'hearing'): self.hearing.recache_n_comments() def check_commenting(self, request): """ Check whether the given request (HTTP or DRF) is allowed to comment on this Commentable. If commenting is not allowed, the function must raise a ValidationError. It must never return a value other than None. """ is_authenticated = request.user.is_authenticated() if self.commenting == Commenting.NONE: raise ValidationError(_("%s does not allow commenting") % self, code="commenting_none") elif self.commenting == Commenting.REGISTERED: if not is_authenticated: raise ValidationError(_("%s does not allow anonymous commenting") % self, code="commenting_registered") elif self.commenting == Commenting.OPEN: return else: # pragma: no cover raise NotImplementedError("Not implemented") def check_voting(self, request): """ Check whether the given request (HTTP or DRF) is allowed to vote on this Commentable. If voting is not allowed, the function must raise a ValidationError. It must never return a value other than None. """ is_authenticated = request.user.is_authenticated() if self.voting == Commenting.NONE: raise ValidationError(_("%s does not allow voting") % self, code="voting_none") elif self.voting == Commenting.REGISTERED: if not is_authenticated: raise ValidationError(_("%s does not allow anonymous voting") % self, code="voting_registered") elif self.voting == Commenting.OPEN: return else: # pragma: no cover raise NotImplementedError("Not implemented") class Meta: abstract = True
class SavedViewConfig(models.Model): theme_identifier = models.CharField(max_length=64, db_index=True, verbose_name=_("theme identifier")) shop = models.ForeignKey("shuup.Shop", related_name="saved_views_config", null=True) view_name = models.CharField(max_length=64, db_index=True, verbose_name=_("view name")) created_on = models.DateTimeField(auto_now_add=True, verbose_name=_("created on")) status = EnumIntegerField(SavedViewConfigStatus, db_index=True, verbose_name=_("status")) _data = TaggedJSONField(db_column="data", default=dict, verbose_name=_("internal data")) objects = SavedViewConfigQuerySet.as_manager() @property def draft(self): return self.status == SavedViewConfigStatus.CURRENT_DRAFT def publish(self): if not self.draft: raise ValueError( "Unable to publish a non-draft view configuration") self.__class__.objects.filter( shop=self.shop, theme_identifier=self.theme_identifier, view_name=self.view_name).update( status=SavedViewConfigStatus.OLD_VERSION) self.status = SavedViewConfigStatus.PUBLIC self.save() def revert(self): if not self.draft: raise ValueError("Unable to revert a non-draft view configuration") if self.pk: self.delete() def set_layout_data(self, layout_data_key, layout): if not layout: # pragma: no cover self._data.setdefault("layouts", {}).pop(layout_data_key, None) return None if not self.draft: raise ValueError("Unable to save things in non-draft mode!") if hasattr(layout, "serialize"): layout = layout.serialize() assert isinstance(layout, dict) self._data.setdefault("layouts", {})[layout_data_key] = layout def get_layout_data(self, layout_data_key): return self._data.get("layouts", {}).get(layout_data_key) def clear_layout_data(self, placeholder_name): if not self.draft: raise ValueError("Unable to save things in non-draft mode!") self._data.setdefault("layouts", {}).pop(placeholder_name, None)
class StoredBoleto(models.Model): order = models.OneToOneField('shuup.Order', related_name='boleto', on_delete=models.CASCADE, verbose_name=_('Pedido')) status = EnumIntegerField(BoletoStatus, verbose_name=_('Situação'), default=BoletoStatus.Created, blank=True) bank_service = EnumField(BankService, verbose_name=_('Serviço')) due_date = models.DateField(verbose_name=_('Data do vencimento')) number_line = models.CharField( verbose_name=_('Linha digitável'), max_length=54, null=True, help_text=_("Linha digitável formatada (54 caracteres)")) bar_code = models.CharField(verbose_name=_('Código de barras'), max_length=44, null=True) nosso_numero = models.CharField(verbose_name=_('Nosso número'), max_length=50, null=True) info = JSONField(verbose_name=_('Informações do boleto'), null=True) total = MoneyProperty('total_value', 'order.currency') total_value = MoneyValueField(editable=False, verbose_name=_('Valor do Boleto'), default=0) payment_date = models.DateTimeField(_('Data do pagamento'), null=True, blank=True) payment_amount = MoneyProperty('payment_amount_value', 'order.currency') payment_amount_value = MoneyValueField(editable=False, verbose_name=_('Valor pago'), default=0) class Meta: verbose_name = _('Boleto bancário') verbose_name_plural = _('Boletos bancários') @property def html(self): """ Retrieves the rendered HTML for the StoredBoleto """ html = '' # se for CECRED.. if self.bank_service == BankService.CECRED: from python_boleto.cecred import CecredBoleto boleto = CecredBoleto(**self.info) boleto.validate() html = boleto.export_html() return html
class Migration(migrations.Migration): dependencies = [ ("batchrun", "0004_logentry_kind_2"), ] operations = [ migrations.AlterField( model_name="jobrunlogentry", name="kind2", field=EnumIntegerField(enum=LogEntryKind, verbose_name="kind"), ), migrations.RemoveField(model_name="jobrunlogentry", name="kind"), migrations.RenameField("jobrunlogentry", "kind2", new_name="kind"), ]
class Migration(migrations.Migration): dependencies = [ ("batchrun", "0002_add_safedelete_to_logs"), ] operations = [ migrations.AlterField( # (*) Add default value to "kind" field model_name="jobrunlogentry", name="kind", field=models.CharField(max_length=30, default="stdout"), ), migrations.AddField( model_name="jobrunlogentry", name="kind2", field=EnumIntegerField(enum=LogEntryKind, default=LogEntryKind.STDOUT, verbose_name="kind"), ), ]
class EventsIndexPage(Page): type = _('Events') data_source = EnumIntegerField(DataSources, verbose_name=_('Event data source'), default=DataSources.LINKEDEVENTS) facebook_page_id = models.CharField(default='1415745085336451', max_length=200) linkedevents_params = models.CharField( default='?keyword=yso:p8692,yso:p26655', max_length=200) content_panels = Page.content_panels + [ FieldPanel('data_source'), FieldPanel('facebook_page_id'), FieldPanel('linkedevents_params'), ] urls = { DataSources.FACEBOOK: "graph.facebook.com/v2.5/", DataSources.LINKEDEVENTS: "api.hel.fi/linkedevents/v1/" } def _facebook_events(self): if not hasattr(settings, 'FACEBOOK_APP_ID') or not hasattr( settings, 'FACEBOOK_APP_SECRET'): return [] events = cache.get('facebook') if events: return events events = [] # facebook feed returns events latest first url = 'https://{}{}?fields=feed{{link,message,object_id}}&access_token={}|{}'.format( self.urls[self.data_source], self.facebook_page_id, str(settings.FACEBOOK_APP_ID), settings.FACEBOOK_APP_SECRET) feed = requests.get(url).json()['feed']['data'] # filter the events from the feed for item in feed: if 'link' in item: if 'https://www.facebook.com/events/' in str(item['link']): events.append(item) # fetch details for the events event_ids = ','.join([event['object_id'] for event in events]) details = [] url = 'https://{}?ids={}&fields=description,cover,end_time,name,start_time,id,picture,place&access_token={}|{}'.format( self.urls[self.data_source], event_ids, str(settings.FACEBOOK_APP_ID), settings.FACEBOOK_APP_SECRET) details = requests.get(url).json() for event in events: event['details'] = details[event['object_id']] cache.add('facebook', events, 3600) return events def _linked_events(self): events = cache.get('linkedevents') if events: return events # the methods are assumed to return events latest first url = 'https://{}event/{}&include=location&sort=-end_time&page_size=100'.format( self.urls[self.data_source], self.linkedevents_params) event_list = requests.get(url).json() events = event_list.get('data') # we will be happy with 100 latest events for now cache.add('linkedevents', events, 3600) return events _event_methods = { DataSources.FACEBOOK: _facebook_events, DataSources.LINKEDEVENTS: _linked_events } def events(self, future=False): try: events = self._event_methods[self.data_source](self) except (TimeoutError, ConnectionError, LookupError): # if the event source is unreachable or down or data is invalid events = [] if not future: return json.dumps(events) # the methods are assumed to return events latest first, reverse the order tz = pytz.timezone(settings.TIME_ZONE) for event in events: # for future filtering, make sure all events have end times not null try: end = event['end_time'] if not end: event['end_time'] = event['start_time'] except LookupError: event['end_time'] = event['start_time'] # check the datetimes first start = dateparse.parse_datetime(event['start_time']) end = dateparse.parse_datetime(event['end_time']) # linkedevents may not have exact times, parse_datetime may fail # we have to append time, assume server time zone and convert to utc for filtering if not start: start = tz.localize( datetime.combine(dateparse.parse_date(event['start_time']), time())) event['start_time'] = start.astimezone( pytz.utc).strftime('%Y-%m-%dT%H:%M:%SZ') if not end: end = tz.localize( datetime.combine(dateparse.parse_date(event['end_time']), time(23, 59, 59))) event['end_time'] = end.astimezone( pytz.utc).strftime('%Y-%m-%dT%H:%M:%SZ') # we want the next event first return json.dumps( list( reversed([ event for event in events if dateparse.parse_datetime( event['end_time']) > datetime.now(tz) ])))
class Market(models.Model): name = models.CharField(max_length=255, default='Market name here. ') description = models.CharField(max_length=1024, default='Market description here. ') pub_date = models.DateTimeField('Date Published') type = EnumIntegerField(MarketType, default=MarketType.msr_maker) def type_string(self): return MarketType.str(self.type) def challenge_end(self): if self.is_active(): return self.active_set().challenge_end() else: return None def challenge_end_ticks(self): """ Gets the challenge_end datetime in the form of ticks elapsed since the Epoch. """ t = self.challenge_end() if t: return int(time.mktime(t.timetuple()) * 1000) else: return None def challenge_start_ticks(self): """ Gets the challenge_start datetime in the form of ticks elapsed since the Epoch. """ t = self.challenge_start() if t: return int(time.mktime(t.timetuple()) * 1000) else: return None def challenge_start(self): if self.is_active(): return self.active_set().challenge_start else: return None def active_set(self): "Gets the active dataset for this market, or None if the market is inactive. " try: return self.dataset_set.get(market=self, is_active=True) except ObjectDoesNotExist: return None except MultipleObjectsReturned: raise Exception("Too many active datasets! Invalid state?.. ") def active_datum(self): set = self.active_set() if not set: return None return set.active_datum() def n_events(self): "Gets the total amount of events registered with this market. " return Event.objects.filter(market=self).count() def n_datasets(self): "Gets the total number of datasets for this market. " return DataSet.objects.filter(market=self).count() def primary_account(self, u): "Returns the user's primary account for this market, or None if they are not registered. " if u.is_anonymous(): return None try: return u.account_set.get(market=self, is_primary=True) except Account.DoesNotExist: return None except MultipleObjectsReturned: raise Exception("Too many accounts for this user! Invalid state?.. ") def create_primary_account(self, u): "Creates a primary account for the given user. Throws an exception if the account exists. " assert not self.primary_account(u) a = Account(user=u, market=self, is_primary=True, funds=100) a.save() return a def api_accounts(self, u): "Gets all API accounts created by the given user for this market. " return u.account_set.filter(is_primary=False) def is_active(self): "Gets whether this market has an active dataset. " return self.active_set() != None is_active.boolean = True # show it as an icon in the admin panel def parse_bid(self, post): """ Parses the data from the given POST request. Returns a list of tuples containing the amount wagered on each outcome for this market. """ pos = [] outcomes = Outcome.objects.filter(event__market=self) for out in outcomes: try: ord_pos = int(post["pos_%i" % (out.id)]) except: ord_pos = 0 if ord_pos != 0: pos.append((out, ord_pos)) return pos def __str__(self): return self.name def save(self, *args, **kwargs): # Sets the pub_date field the first time the object is saved if self.pub_date == None: self.pub_date = timezone.now() super(Market, self).save()
def test_django_admin_lookup_value_for_integer_enum_field(): field = EnumIntegerField(MyModel.Taste) assert field.get_prep_value(str(MyModel.Taste.BITTER)) == 3, "get_prep_value should be able to convert from strings"
class BoletoBehaviorComponentMixin(models.Model): bank_service = None num_sequencial = models.BigIntegerField( verbose_name=_('Número sequencial do próximo boleto'), help_text= _('Este número será utilizado caso ele seja maior do que o último armazenado. ' 'Se ele for menor, este será desconsiderado. CUIDADO: apenas informe este campo ' 'se você sabe o que está fazendo. O objetivo é ajustar o número sequencial ' 'inicial caso boletos já tenham sido emitidos anteriormente através de outro software.' ), default=1) local_pagamento = models.TextField(verbose_name=_('Local de pagamento'), max_length=60) cedente = models.TextField(verbose_name=_('Nome do cedente'), max_length=60, help_text=_('É o emissor do título')) prazo_vencimento = models.PositiveSmallIntegerField( verbose_name=_('Prazo para o vencimento do boleto'), default=5, help_text=_('Quantidade de dias que será adicionado a ' 'data do pedido para atribuir como vencimento do boleto.')) instrucoes = models.TextField( verbose_name=_('Instruções'), max_length=60, blank=True, null=True, help_text=_('Máximo de 8 linhas com 50 caracteres cada.')) especie_doc = EnumIntegerField(DocumentType, verbose_name=_('Espécie do documento'), default=DocumentType.DM) class Meta: abstract = True def get_context_data(self, service, order): boleto_data = { "valor_documento": order.taxful_total_price.value, "data_documento": order.created_on.date(), "numero_documento": order.pk, "especie": "R$", "sacado": str(order.billing_address), "aceite": 'N', "local_pagamento": self.local_pagamento, "especie_doc": self.especie_doc, "vencimento": order.created_on.date() + timedelta(days=self.prazo_vencimento), "cedente": self.cedente, "instrucoes": self.instrucoes.split("\n") if self.instrucoes else [] } # Adiciona endereço melhor formatado # e informações complementares no sacado # quando Shuup BR estiver instalado if "shuup_br" in settings.INSTALLED_APPS: try: from shuup_br.models import PersonType person_id = '' if order.creator.person_type == PersonType.FISICA: person_id = order.creator.pf_person.cpf elif order.creator.person_type == PersonType.JURIDICA: person_id = order.creator.pj_person.cnpj sacado = order.billing_address.name if person_id: sacado = "{0} - {1}".format(sacado, person_id) sacado_extra = [] has_extra = hasattr(order.billing_address, 'extra') sacado_extra = [ "{0}, {1} - {2} - {3} - {4}".format( order.billing_address.street, order.billing_address.extra.numero if has_extra else '', order.billing_address.street2, order.billing_address.street3, order.billing_address.postal_code), "{0} - {1} - {2}".format(order.billing_address.city, order.billing_address.region, order.billing_address.country) ] boleto_data["sacado"] = sacado boleto_data["sacado_extra"] = sacado_extra except: pass return boleto_data def generate_boleto(self, service, order): if not self.bank_service: raise AttributeError("bank_service must be set to a valid value") boleto_data = self.get_context_data(service, order) with transaction.atomic(): stored_boleto = StoredBoleto.objects.create( order=order, due_date=boleto_data['vencimento'], bank_service=self.bank_service, total_value=order.taxful_total_price.value) return stored_boleto def next_sequence(self): with transaction.atomic(): # Gera o numero sequencial do boleto # de acordo com o servico seq, created = BoletoSequenceNumber.objects.get_or_create( bank_service=self.bank_service, defaults={'last_number': self.num_sequencial or 1}) if not created: seq.last_number = F('last_number') + 1 seq.save(update_fields=['last_number']) seq.refresh_from_db() return seq.last_number