예제 #1
0
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
예제 #2
0
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)
예제 #3
0
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
예제 #4
0
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"),
    ]
예제 #5
0
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"),
        ),
    ]
예제 #6
0
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)
                ])))
예제 #7
0
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()
예제 #8
0
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"
예제 #9
0
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