Projet

Général

Profil

0001-forms-implement-locked-fields-by-renaming-and-widget.patch

Benjamin Dauvergne, 18 juin 2019 00:18

Télécharger (5,42 ko)

Voir les différences:

Subject: [PATCH] forms: implement locked fields by renaming and widget change
 (#32954)

It simplifies the code (no need to implement a special clean() method)
and it covers the case of field with widget not supporting the readonly
HTML attribute like those based on <select> or <input type="radio">
tags.
 src/authentic2/forms/profile.py | 57 ++++++++++++++++++++++++---------
 tests/test_profile.py           | 20 ++++++++++++
 2 files changed, 61 insertions(+), 16 deletions(-)
src/authentic2/forms/profile.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from collections import OrderedDict
17 18

  
18 19
from django.forms.models import modelform_factory as dj_modelform_factory
19 20
from django import forms
......
76 77

  
77 78
        self.attributes = models.Attribute.objects.all()
78 79
        initial = kwargs.setdefault('initial', {})
79
        if kwargs.get('instance'):
80
            instance = kwargs['instance']
81
            for av in models.AttributeValue.objects.with_owner(instance):
82
                if av.attribute.name in self.declared_fields:
83
                    if av.verified:
84
                        self.declared_fields[av.attribute.name].widget.attrs['readonly'] = 'readonly'
85
                    initial[av.attribute.name] = av.to_python()
80
        instance = kwargs.get('instance')
81
        # extended attributes are not model fields, their initial value must be
82
        # explicitely defined
83
        for av in models.AttributeValue.objects.select_related('attribute').with_owner(instance):
84
            name = av.attribute.name
85
            if name in self.declared_fields:
86
                initial[name] = av.to_python()
86 87
        super(BaseUserForm, self).__init__(*args, **kwargs)
87

  
88
    def clean(self):
89
        from authentic2 import models
90

  
91
        # make sure verified fields are not modified
92
        for av in models.AttributeValue.objects.with_owner(
93
                self.instance).filter(verified=True):
94
            self.cleaned_data[av.attribute.name] = av.to_python()
95
        super(BaseUserForm, self).clean()
88
        if instance:
89
            # Locked attributes are modified to use a read-only TextInput
90
            # widget remapped to a name which will be ignored by Form
91
            # implementation
92
            modified_fields = {}
93
            for av in models.AttributeValue.objects.select_related('attribute').with_owner(instance):
94
                name = av.attribute.name
95
                if name in self.fields and av.verified:
96
                    old_field = self.fields[name]
97
                    initial = self.initial[name]
98
                    try:
99
                        choices = old_field.choices
100
                    except AttributeError:
101
                        initial = old_field.widget.format_value(initial)
102
                    else:
103
                        for key, label in choices:
104
                            if initial == key:
105
                                initial = label
106
                                break
107

  
108
                    modified_fields[av.attribute.name] = forms.CharField(
109
                        label=old_field.label,
110
                        help_text=old_field.help_text,
111
                        initial=initial,
112
                        widget=forms.TextInput(attrs={'readonly': ''}))
113
            if modified_fields:
114
                new_fields = OrderedDict()
115
                for name in self.fields:
116
                    if name not in modified_fields:
117
                        new_fields[name] = self.fields[name]
118
                        continue
119
                    new_fields[name + '@disabled'] = modified_fields[name]
120
                self.fields = new_fields
96 121

  
97 122
    def save_attributes(self):
98 123
        # only save non verified attributes here
tests/test_profile.py
135 135
    resp = app.get(reverse('profile_edit_with_scope', kwargs={'scope': 'address'}),
136 136
                   status=200)
137 137
    assert get_fields(resp) == set(['city', 'zipcode', 'next_url'])
138

  
139

  
140
def test_account_edit_locked_title(app, simple_user):
141
    Attribute.objects.create(
142
        name='title', label='title',
143
        kind='title', user_visible=True, user_editable=True)
144
    simple_user.attributes.title = 'Monsieur'
145

  
146
    utils.login(app, simple_user)
147
    url = reverse('profile_edit')
148
    response = app.get(url, status=200)
149
    assert len(response.pyquery('input[type="radio"][name="edit-profile-title"]')) == 2
150
    assert len(response.pyquery('input[type="radio"][name="edit-profile-title"][readonly="true"]')) == 0
151
    assert len(response.pyquery('select[name="edit-profile-title"]')) == 0
152

  
153
    simple_user.verified_attributes.title = 'Monsieur'
154

  
155
    response = app.get(url, status=200)
156
    assert len(response.pyquery('input[type="radio"][name="edit-profile-title"][readonly=true]')) == 0
157
    assert len(response.pyquery('select[name="edit-profile-title"]')) == 1
138
-