Esempio n. 1
0
 def _formfield(self, initial):
     return TypedChoiceField(
         choices=self._args['choices'],
         coerce=int,
         initial=initial,
         empty_value=None,
     )
Esempio n. 2
0
 def _formfield(self, initial):
     return TypedChoiceField(
         choices=self._CHOICES.items(),
         coerce=int,
         widget=RadioSelect,
         initial=initial,
         empty_value=None,
     )
Esempio n. 3
0
    def __init__(self, section=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.section = section

        # Lines which are in the section where we create our line.
        self.section_lines = section_lines = []

        # The lines after the one we create (but not in the same section):
        # their order have to be incremented
        self.next_lines = next_lines = []

        # Order of the last line before our section (used if our section is empty).
        self.empty_section_order = 1

        nodes = [*SectionTree(self.pform)]
        section_id = section.id if section else None

        # Filling of 'section_lines' & 'next_lines'
        node_it = reversed(nodes)
        try:
            while True:
                node = next(node_it)

                if not node.is_section:
                    if node.section_id == section_id:
                        section_lines.append(node)
                    else:
                        next_lines.append(node)
                elif node.id == section_id:
                    previous_line = find_first(
                        node_it, (lambda node: not node.is_section), None)

                    if previous_line:
                        self.empty_section_order = previous_line.order + 1

                    break
        except StopIteration:
            pass

        if section_lines:
            section_lines.reverse()

            # TODO: cached_gettext ??
            msg_fmt = gettext('Before: «{question}» (#{number})').format
            choices = [
                (0, gettext('Start of section')),
                *((i, msg_fmt(question=node.question, number=node.number))
                  for i, node in enumerate(section_lines[1:], start=1)),
                (len(section_lines), gettext('End of section')),
            ]

            self.fields['index'] = TypedChoiceField(
                label=gettext('Order'),
                coerce=int,
                choices=choices,
                initial=len(choices) - 1,
            )
Esempio n. 4
0
    def __init__(self, *args, model_instance=None, **kwargs):

        result = super().__init__(*args, **kwargs)

        self.fields['status'] = TypedChoiceField(
            choices=Task.STATUS_CHOICES,
            initial=model_instance and model_instance.status or None,
            label='',
            widget=StatusChoice(
                instance_pk=model_instance and model_instance.pk or None))

        return result
Esempio n. 5
0
class PollFormLineConditionsForm(CremeForm):
    use_or = TypedChoiceField(
        label=_('Use OR or AND between conditions'),
        choices=[(0, _('AND')), (1, _('OR'))],
        coerce=(lambda x: bool(int(x))),
        widget=CremeRadioSelect,
    )
    conditions = PollFormLineConditionsField(label=_('Conditions'),
                                             required=False)

    def __init__(self, entity, line, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.line = line
        self.old_conditions = conditions = line.get_conditions()

        fields = self.fields
        # TODO: remove 'bool' if no more nullable
        fields['use_or'].initial = int(bool(line.conds_use_or))

        conditions_f = fields['conditions']
        conditions_f.sources = entity.lines.filter(order__lt=line.order)
        conditions_f.initial = conditions

    def save(self, *args, **kwargs):
        line = self.line
        cdata = self.cleaned_data

        update_model_instance(line, conds_use_or=cdata['use_or'])

        conds2del = []

        # TODO: select for update ??
        for old_condition, condition in zip_longest(self.old_conditions,
                                                    cdata['conditions']):
            if not condition:
                # Less new conditions that old conditions => delete conditions in excess
                conds2del.append(old_condition.id)
            elif not old_condition:
                condition.line = line
                condition.save()
            elif old_condition.update(condition):
                old_condition.save()

        if conds2del:
            PollFormLineCondition.objects.filter(pk__in=conds2del).delete()
Esempio n. 6
0
class PollFormLineCreateForm(_PollFormLineForm):
    type = TypedChoiceField(
        label=_('Type'),
        choices=PollLineType.choices(),
        coerce=int,
        initial=PollLineType.STRING,
    )
    lower_bound = IntegerField(
        label=_('Lower bound'),
        required=False,
        help_text=_('For integer type only.'),
    )
    upper_bound = IntegerField(
        label=_('Upper bound'),
        required=False,
        help_text=_('For integer type only.'),
    )
    choices = CharField(
        widget=Textarea(),
        label=_('Available choices'),
        required=False,
        help_text=_('Give the possible choices (one per line) '
                    'if you choose the type "Choice list".'),
    )

    def __init__(self, section=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.section = section
        self.section_lines = section_lines = [
        ]  # Lines which are in the section where we create our line
        self.next_lines = next_lines = [
        ]  # The lines after the one we create (but not in the same section):
        # their order have to be incremented
        self.empty_section_order = 1  # Order of the last line before our section (used if our section is empty)

        nodes = [*SectionTree(self.pform)]
        section_id = section.id if section else None

        # Filling of 'section_lines' & 'next_lines'
        node_it = reversed(nodes)
        try:
            while True:
                node = next(node_it)

                if not node.is_section:
                    if node.section_id == section_id:
                        section_lines.append(node)
                    else:
                        next_lines.append(node)
                elif node.id == section_id:
                    previous_line = find_first(
                        node_it, (lambda node: not node.is_section), None)

                    if previous_line:
                        self.empty_section_order = previous_line.order + 1

                    break
        except StopIteration:
            pass

        if section_lines:
            section_lines.reverse()

            msg_fmt = gettext('Before: «{question}» (#{number})'
                              ).format  # TODO: cached_gettext ??
            choices = [
                (0, gettext('Start of section')),
                *((i, msg_fmt(question=node.question, number=node.number))
                  for i, node in enumerate(section_lines[1:], start=1)),
                (len(section_lines), gettext('End of section'))
            ]

            self.fields['index'] = TypedChoiceField(
                label=gettext('Order'),
                coerce=int,
                choices=choices,
                initial=len(choices) - 1,
            )

    def clean(self):
        cleaned_data = super().clean()

        if not self._errors:
            get_data = cleaned_data.get
            self.type_args = PollLineType.build_serialized_args(
                ptype=cleaned_data['type'],
                lower_bound=get_data('lower_bound'),
                upper_bound=get_data('upper_bound'),
                choices=[
                    *enumerate(
                        filter(None, (choice.strip() for choice in get_data(
                            'choices', '').split('\n'))),
                        start=1,
                    )
                ],
            )  # Can raise Validation errors

        return cleaned_data

    def save(self, *args, **kwargs):
        cdata = self.cleaned_data
        section_lines = self.section_lines

        if not section_lines:
            index = 0
            order = self.empty_section_order
        else:
            index = cdata['index']

            if index < len(section_lines):
                order = section_lines[index].order
            else:
                order = section_lines[-1].order + 1

        instance = self.instance
        instance.pform = self.pform
        instance.section = self.section
        instance.order = order
        instance.type = cdata['type']
        instance.type_args = self.type_args

        for line in chain(section_lines[index:], self.next_lines):
            line.order += 1
            line.save()

        return super().save(*args, **kwargs)
Esempio n. 7
0
class EventModelForm(ModelForm):
    update_date = DateTimeField(
        input_formats=(DATE_FORMAT, ),
        widget=widgets.DateTimeInput(format=DATE_FORMAT))
    foia = TypedChoiceField(empty_value=None,
                            initial=None,
                            coerce=lambda pk: Foia.objects.get(pk=pk))
    email = ModelChoiceField(queryset=InboundEmail.objects.all(),
                             required=False,
                             widget=widgets.HiddenInput)

    def __init__(self, *args, **kwargs):
        super(EventModelForm, self).__init__(*args, **kwargs)

        if 'initial' in kwargs and 'email' in kwargs['initial']:
            email = InboundEmail.objects.filter(
                pk=kwargs['initial']['email']).select_related(
                    'sender').first()

            sender_projects = Project.objects.filter(
                collaborators=email.sender).values_list('pk', flat=True)

            prefix_re = re.compile('(re|fwd):', flags=re.IGNORECASE)
            generic_language_re = re.compile(
                r'((?:tpia|record(?:s)*|foia|public\s+information)\s+request)(?!\s+log(?:s)*)',
                flags=re.IGNORECASE | re.VERBOSE)

            def strip_subject(subject):
                prefix_removed = prefix_re.sub('', subject)
                generics_removed = generic_language_re.sub('', prefix_removed)
                return ''.join(_ for _ in generics_removed
                               if _.isalpha() or _ == ' ')

            cleaned_email_subject = strip_subject(email.subject)

            def match_email_to_foia(foia):
                score = fuzz.ratio(
                    strip_subject(foia['request_subject']),
                    cleaned_email_subject,
                )

                # Boost the score if the sender is the same and for requests
                # that are in one of the sender's projects
                if foia['email__sender__pk'] == email.sender.pk:
                    score += 25
                elif foia['project__pk'] is not None and \
                        foia['project__pk'] in sender_projects:
                    score += 20

                days_apart = (email.sent.date() - foia['sent']).days

                # Penalize requests that are older than 30 days, but max out
                # the penalty at the 180-day mark
                min_days = 30
                max_days = 180
                normalized_days_apart = min(max(min_days, days_apart),
                                            max_days) - min_days
                score *= (1 - float(normalized_days_apart) / float(max_days))

                return score

            all_foias = Foia.objects.all().select_related(
                'email', 'email__sender').values(
                    'pk',
                    'sent',
                    'request_subject',
                    'email__sender__pk',
                    'email__sender__last_name',
                    'project__pk',
                )

            for foia in all_foias:
                foia['label'] = '%s: %s' % (
                    foia['email__sender__last_name'],
                    foia['request_subject'],
                )

            ranked_foias = sorted(all_foias,
                                  key=match_email_to_foia,
                                  reverse=True)

            self.fields['foia'].choices = [(
                f['pk'],
                f['label'],
            ) for f in ranked_foias]
        else:
            self.fields['foia'].choices = Foia.objects.all().select_related(
                'email__sender').values_list('pk', 'request_subject')

    class Meta:
        model = Event
        fields = (
            'foia',
            'status',
            'update_date',
            'amount_asked',
            'amount_paid',
            'notes',
            'email',
        )
        widgets = {'status': RadioSelect(choices=Event.STATUS_CHOICES)}
Esempio n. 8
0
class CartAddProductForm(forms.Form):
    quantity = TypedChoiceField(choices=PRODUCT_QUANTITY_CHOICES, coerce=int)
    override = forms.BooleanField(required=False,
                                  initial=False,
                                  widget=forms.HiddenInput)
Esempio n. 9
0
class UserSettingsConfigForm(CremeForm):
    url = URLField(label=_(u'Server URL'), required=False)
    url_examples = ChoiceField(
        label=_(u'Server URL examples'),
        required=False,
        help_text=_(u'Some common configurations'),
        choices=chain((("", ""), ), COMMONS_SERVER_URL_CFG),
        widget=Select(
            attrs={'onchange': 'this.form.url.value=$(this).val();'}),
    )
    domain = CharField(label=_(u'Domain'), required=False)
    ssl = ChoiceField(
        label=_(u'Is secure'),
        required=False,
        choices=(('', _('Default')), (1, _('Yes')), (0, _('No'))),
    )
    login = CharField(label=_(u'Login'), required=False)
    password = CharField(label=_(u'Password'),
                         required=False,
                         widget=PasswordInput)
    sync_calendars = TypedChoiceField(
        label=_(u'Synchronize activities (calendars)'),
        help_text=_(u'Choose if either you want to synchronize '
                    u'your activities in both way or not.'),
        choices=_BOOL_CHOICES,
        coerce=_choice_2_bool,
    )
    sync_contacts = TypedChoiceField(
        label=_(u'Synchronize contacts'),
        help_text=_(u'Choose if either you want to synchronize '
                    u'your contacts in both way or not.'),
        choices=_BOOL_CHOICES,
        coerce=_choice_2_bool,
    )

    blocks = FieldBlockManager(
        ('mobile_sync', _(u'Mobile synchronization configuration'), '*'),
        ('what_sync', _(u'What to sync'), ('sync_calendars', 'sync_contacts')),
    )

    def __init__(self, *args, **kwargs):
        super(UserSettingsConfigForm, self).__init__(*args, **kwargs)
        # user = self.user

        # self._svalues_cache = svalues_cache = {}
        # sv_get = SettingValue.objects.get

        # def get_svalue(key_id):
        #     sv = svalues_cache[key_id] = sv_get(key_id=key_id, user=user)
        #     return sv

        fields = self.fields

        user_settings = self.user.settings
        # sv_doesnotexist = SettingValue.DoesNotExist

        def_svalues = get_default_server_setting_values()
        let_empty_msg = ugettext(
            u"Let empty to get the default configuration (currently '%s').")

        url_field = fields['url']
        # url_field.help_text = let_empty_msg % sv_get(key_id=MAPI_SERVER_URL).value
        url_field.help_text = let_empty_msg % (def_svalues['url'].value or '')
        # try:
        #     url_field.initial = get_svalue(USER_MOBILE_SYNC_SERVER_URL).value
        # except sv_doesnotexist:
        #     pass
        url_field.initial = self._old_url = user_settings.get(
            user_msync_server_url_key, '')

        domain_field = fields['domain']
        # domain_field.help_text = let_empty_msg % sv_get(key_id=MAPI_DOMAIN).value
        domain_field.help_text = let_empty_msg % (def_svalues['domain'].value
                                                  or '')
        # try:
        #     domain_field.initial = get_svalue(USER_MOBILE_SYNC_SERVER_DOMAIN).value
        # except sv_doesnotexist:
        #     pass
        domain_field.initial = user_settings.get(user_msync_server_domain_key,
                                                 '')

        ssl_field = fields['ssl']
        ssl_field.help_text = ugettext(
            u"Let 'Default' to get the default configuration (currently '%s')."
        ) % (
            # ugettext('Yes') if sv_get(key_id=MAPI_SERVER_SSL).value else ugettext('No')
            ugettext('Yes') if def_svalues['ssl'].value else ugettext('No'))
        # try:
        #     ssl_field.initial = int(get_svalue(USER_MOBILE_SYNC_SERVER_SSL).value)
        # except sv_doesnotexist:
        #     pass
        ssl_field.initial = int(
            user_settings.get(user_msync_server_ssl_key, False))

        # ----------------------------------
        # try:
        #     fields['login'].initial = get_svalue(USER_MOBILE_SYNC_SERVER_LOGIN).value
        # except sv_doesnotexist:
        #     pass
        fields['login'].initial = self._old_login = user_settings.get(
            user_msync_server_login_key, '')

        pwd_field = fields['password']
        # try:
        #     pwd_field.initial = Cipher.decrypt_from_db(get_svalue(USER_MOBILE_SYNC_SERVER_PWD).value)
        #     pwd_field.widget.render_value = True
        # except sv_doesnotexist:
        #     pass
        try:
            pwd_field.initial = Cipher.decrypt_from_db(
                user_settings[user_msync_server_pwd_key])
        except KeyError:
            pass
        else:
            pwd_field.widget.render_value = True

        # try:
        #     fields['sync_calendars'].initial = int(get_svalue(USER_MOBILE_SYNC_ACTIVITIES).value)
        # except sv_doesnotexist:
        #     pass
        fields['sync_calendars'].initial = int(
            user_settings.get(user_msync_activities_key, False))

        # try:
        #     fields['sync_contacts'].initial = int(get_svalue(USER_MOBILE_SYNC_CONTACTS).value)
        # except sv_doesnotexist:
        #     pass
        fields['sync_contacts'].initial = int(
            user_settings.get(user_msync_contacts_key, False))

    def clean_ssl(self):
        try:
            return _choice_2_bool(self.cleaned_data['ssl'])
        except ValueError:
            pass

    def save(self):
        user = self.user
        clean_get = self.cleaned_data.get

        # url_is_created   = False
        # login_is_created = False

        # def upgrade_svalue(key_id, value):
        #     svalue = self._svalues_cache.get(key_id)
        #     created = False
        #
        #     if svalue is None:
        #         svalue = self._svalues_cache[key_id] \
        #                = SettingValue.objects.create(key_id=key_id, user=user, value=value)
        #         created = True
        #     elif svalue.value != value:
        #         svalue.value = value
        #         svalue.save()
        #
        #     return created
        #
        # def delete_svalue(key_id):
        #     svalue = self._svalues_cache.pop(key_id, None)
        #
        #     if svalue is not None:
        #         svalue.delete()

        url = clean_get('url')
        # if url:
        #     url_is_created = upgrade_svalue(USER_MOBILE_SYNC_SERVER_URL, url)
        # else:
        #     delete_svalue(USER_MOBILE_SYNC_SERVER_URL)

        domain = clean_get('domain')
        # if domain:
        #     upgrade_svalue(USER_MOBILE_SYNC_SERVER_DOMAIN, domain)
        # else:
        #     delete_svalue(USER_MOBILE_SYNC_SERVER_DOMAIN)

        ssl = clean_get('ssl')
        # if ssl is not None:
        #     upgrade_svalue(USER_MOBILE_SYNC_SERVER_SSL, ssl)
        # else:
        #     delete_svalue(USER_MOBILE_SYNC_SERVER_SSL)

        login = clean_get('login')
        # if login:
        #     login_is_created = upgrade_svalue(USER_MOBILE_SYNC_SERVER_LOGIN, login)
        # else:
        #     delete_svalue(USER_MOBILE_SYNC_SERVER_LOGIN)

        # upgrade_svalue(USER_MOBILE_SYNC_ACTIVITIES, clean_get('sync_calendars'))
        # upgrade_svalue(USER_MOBILE_SYNC_CONTACTS,   clean_get('sync_contacts'))

        password = clean_get('password')
        # if password:
        #     upgrade_svalue(USER_MOBILE_SYNC_SERVER_PWD, Cipher.encrypt_for_db(password))
        # else:
        #     delete_svalue(USER_MOBILE_SYNC_SERVER_PWD)

        with self.user.settings as user_settings:
            # TODO: factorise
            if url:
                user_settings[user_msync_server_url_key] = url
            else:
                user_settings.pop(user_msync_server_url_key, None)

            if domain:
                user_settings[user_msync_server_domain_key] = domain
            else:
                user_settings.pop(user_msync_server_domain_key, None)

            if ssl is not None:
                user_settings[user_msync_server_ssl_key] = ssl
            else:
                user_settings.pop(user_msync_server_ssl_key, None)

            if login:
                user_settings[user_msync_server_login_key] = login
            else:
                user_settings.pop(user_msync_server_login_key, None)

            user_settings[user_msync_activities_key] = clean_get(
                'sync_calendars')
            user_settings[user_msync_contacts_key] = clean_get('sync_contacts')

            if password:
                user_settings[
                    user_msync_server_pwd_key] = Cipher.encrypt_for_db(
                        password)
            else:
                user_settings.pop(user_msync_server_pwd_key, None)

        # TODO: test
        # TODO: add a true button to purge (ex: we could want to purge if the url is changed, or not)
        # if url_is_created or login_is_created:
        if self._old_url != url or self._old_login != login:
            try:
                as_client = CremeClient.objects.get(user=user)
            except CremeClient.DoesNotExist:
                pass
            else:
                as_client.purge(
                )  # NB: If server_url or login have changed, we reset all mapping & clientdef