Projet

Général

Profil

0001-environment-add-a-deleted-flag-on-variables-32147.patch

Nicolas Roche, 27 juin 2022 10:29

Télécharger (13,2 ko)

Voir les différences:

Subject: [PATCH 1/4] environment: add a deleted flag on variables (#32147)

 hobo/environment/forms.py                     |  2 +-
 .../migrations/0027_auto_20220614_1145.py     | 25 +++++++++++++++++++
 hobo/environment/models.py                    |  3 ++-
 hobo/environment/views.py                     | 13 +++++++++-
 tests/test_environment.py                     | 24 ++++++++++++------
 5 files changed, 56 insertions(+), 11 deletions(-)
 create mode 100644 hobo/environment/migrations/0027_auto_20220614_1145.py
hobo/environment/forms.py
157 157
    class Meta:
158 158
        model = Hobo
159 159
        exclude = EXCLUDED_FIELDS
160 160

  
161 161

  
162 162
class VariableForm(forms.ModelForm):
163 163
    class Meta:
164 164
        model = Variable
165
        exclude = ('service_type', 'service_pk', 'auto')
165
        exclude = ('service_type', 'service_pk', 'auto', 'deleted')
166 166

  
167 167
    def __init__(self, service=None, **kwargs):
168 168
        self.service = service
169 169
        super(VariableForm, self).__init__(**kwargs)
170 170

  
171 171
    def save(self, commit=True):
172 172
        if self.service:
173 173
            self.instance.service = self.service
hobo/environment/migrations/0027_auto_20220614_1145.py
1
# Generated by Django 2.2.26 on 2022-06-14 09:45
2

  
3
from django.db import migrations, models
4

  
5

  
6
class Migration(migrations.Migration):
7

  
8
    dependencies = [
9
        ('environment', '0026_lingo'),
10
    ]
11

  
12
    operations = [
13
        migrations.AddField(
14
            model_name='variable',
15
            name='deleted',
16
            field=models.BooleanField(default=False),
17
        ),
18
        migrations.AlterField(
19
            model_name='variable',
20
            name='value',
21
            field=models.TextField(
22
                blank=True, help_text='start with [ or { for a JSON document', null=True, verbose_name='value'
23
            ),
24
        ),
25
    ]
hobo/environment/models.py
54 54
    'sms_sender',
55 55
)
56 56

  
57 57

  
58 58
class Variable(models.Model):
59 59
    name = models.CharField(max_length=100, verbose_name=_('name'))
60 60
    label = models.CharField(max_length=100, blank=True, verbose_name=_('label'))
61 61
    value = models.TextField(
62
        verbose_name=_('value'), blank=True, help_text=_('start with [ or { for a JSON document')
62
        verbose_name=_('value'), blank=True, null=True, help_text=_('start with [ or { for a JSON document')
63 63
    )
64 64
    auto = models.BooleanField(default=False)
65 65
    service_type = models.ForeignKey(ContentType, null=True, on_delete=models.CASCADE)
66 66
    service_pk = models.PositiveIntegerField(null=True)
67 67
    service = GenericForeignKey('service_type', 'service_pk')
68 68
    last_update_timestamp = models.DateTimeField(auto_now=True, null=True)
69
    deleted = models.BooleanField(default=False)
69 70

  
70 71
    def get_field_label(self):
71 72
        if self.label:
72 73
            return self.label
73 74
        return self.name
74 75

  
75 76
    def _parse_value_as_json(self):
76 77
        if self.value and (
hobo/environment/views.py
58 58
        return context
59 59

  
60 60

  
61 61
class VariablesView(TemplateView):
62 62
    template_name = 'environment/variables.html'
63 63

  
64 64
    def get_context_data(self, **kwargs):
65 65
        context = super(VariablesView, self).get_context_data(**kwargs)
66
        context['variables'] = Variable.objects.filter(auto=False, service_pk__isnull=True).order_by('label')
66
        context['variables'] = Variable.objects.filter(
67
            auto=False, service_pk__isnull=True, deleted=False
68
        ).order_by('label')
67 69
        return context
68 70

  
69 71

  
70 72
class VariableCreateView(CreateView):
71 73
    model = Variable
72 74
    form_class = forms.VariableForm
73 75

  
74 76
    def get_form_kwargs(self):
......
91 93
        else:
92 94
            service_kwargs = {'service_pk__isnull': True}
93 95
        try:
94 96
            self.object = Variable.objects.get(name=form.instance.name, **service_kwargs)
95 97
        except Variable.DoesNotExist:
96 98
            self.object = form.save()
97 99
        else:
98 100
            self.object.auto = False
101
            self.object.deleted = False
99 102
            self.object.value = form.instance.value
100 103
            self.object.save()
101 104
        return HttpResponseRedirect(self.get_success_url())
102 105

  
103 106
    def get_success_url(self):
104 107
        if self.object.service is None:
105 108
            return reverse_lazy('environment-variables')
106 109
        return reverse_lazy('environment-home')
......
120 123
    model = Variable
121 124
    template_name = 'environment/generic_confirm_delete.html'
122 125

  
123 126
    def get_success_url(self):
124 127
        if self.object.service is None:
125 128
            return reverse_lazy('environment-variables')
126 129
        return reverse_lazy('environment-home')
127 130

  
131
    def delete(self, request, *args, **kwargs):
132
        self.object = self.get_object()
133
        success_url = self.get_success_url()
134
        self.object.value = None
135
        self.object.deleted = True
136
        self.object.save()
137
        return HttpResponseRedirect(success_url)
138

  
128 139

  
129 140
class ServiceCreateView(CreateView):
130 141
    success_url = reverse_lazy('environment-home')
131 142

  
132 143
    def get_context_data(self, **kwargs):
133 144
        context = super(ServiceCreateView, self).get_context_data(**kwargs)
134 145
        context['model_name'] = self.model._meta.verbose_name
135 146
        return context
tests/test_environment.py
239 239
    response = response.form.submit()
240 240
    assert response.location == '/sites/variables'
241 241
    assert Variable.objects.all()[0].value == 'barbar'
242 242

  
243 243

  
244 244
def test_variable_delete_view(app, admin_user):
245 245
    app = login(app)
246 246
    var = Variable.objects.create(name='foo', value='bar')
247
    assert var.deleted is False
247 248
    response = app.get('/sites/delete-variable/%s' % var.pk)
248 249
    assert response.html.find('h2').text == 'Removal of "foo"'
249 250
    response = response.form.submit()
250 251
    assert response.location == '/sites/variables'
251
    assert Variable.objects.count() == 0
252
    assert Variable.objects.count() == 1
253
    assert Variable.objects.first().value == None
254
    assert Variable.objects.first().deleted is True
252 255

  
253 256

  
254 257
def test_service_update_view(app, admin_user):
255 258
    app = login(app)
256 259
    Combo.objects.create(
257 260
        base_url='https://combo.agglo.love', template_name='...portal-user...', slug='portal'
258 261
    )
259 262
    response = app.get('/sites/save-combo/portal')
......
342 345

  
343 346

  
344 347
def test_export_import_view(app, admin_user):
345 348
    combo = Combo.objects.create(
346 349
        base_url='https://combo.agglo.love', template_name='...portal-user...', slug='portal'
347 350
    )
348 351
    Variable.objects.create(name='foo', value='bar').save()
349 352
    Variable.objects.create(name='foo2', value='bar2', service=combo).save()
353
    Variable.objects.create(name='fooD', value=None, deleted=True).save()
354

  
350 355
    app = login(app, 'admin', 'password')
351 356
    resp = app.get('/sites/export/', status=200)
352 357
    assert sorted(resp.json.keys()) == ['profile', 'variables']
353
    assert resp.json['variables'] == [{'name': 'foo', 'label': '', 'value': 'bar', 'auto': False}]
358
    assert resp.json['variables'] == [
359
        {'name': 'foo', 'label': '', 'value': 'bar', 'auto': False},
360
        {'name': 'fooD', 'label': '', 'value': None, 'auto': False},
361
    ]
354 362
    assert resp.json['profile']['fields'][0]['name'] == 'title'
355 363
    assert resp.json['profile']['fields'][0]['required'] is False
356 364
    assert resp.json['profile']['fields'][0]['description'] == ''
357 365
    assert resp.json['profile']['fields'][2]['name'] == 'last_name'
358 366
    assert resp.json['profile']['fields'][2]['required'] is True
359 367
    assert resp.json['profile']['fields'][2]['label'] == 'Nom'
360 368

  
361 369
    # modify exported file
......
367 375
    fields[0]['description'] = 'genre'
368 376
    fields[2]['label'] = 'Nom de naissance'
369 377
    fields[0], fields[2] = fields[2], fields[0]
370 378
    export_json = json.dumps(export)
371 379

  
372 380
    # add new content
373 381
    Variable.objects.create(name='foo3', value='bar3').save()
374 382
    AttributeDefinition.objects.create(name='prefered_color', label='not empty').save()
375
    assert Variable.objects.count() == 3
383
    assert Variable.objects.count() == 4
376 384
    assert AttributeDefinition.objects.count() == 12
377 385
    assert Variable.objects.get(name='foo').label == ''
378 386
    assert AttributeDefinition.objects.get(name='title').description == ''
379 387
    assert AttributeDefinition.objects.get(name='title').order == 1
380 388
    assert AttributeDefinition.objects.get(name='last_name').order == 3
381 389
    assert AttributeDefinition.objects.get(name='prefered_color').order == 12
382 390

  
383 391
    # import valid content
384 392
    resp = app.get('/', status=200)
385 393
    resp = resp.click('Import')
386 394
    resp.form['parameters_json'] = Upload('export.json', export_json.encode('utf-8'), 'application/json')
387 395
    resp = resp.form.submit()
388
    assert Variable.objects.count() == 3
396
    assert Variable.objects.count() == 4
389 397
    assert AttributeDefinition.objects.count() == 12
390 398
    assert Variable.objects.get(name='foo').label == 'bar'
391 399
    assert AttributeDefinition.objects.get(name='title').description == 'genre'
392 400
    assert AttributeDefinition.objects.get(name='title').order == 1
393 401
    assert AttributeDefinition.objects.get(name='last_name').label == 'Nom de naissance'
394 402
    assert AttributeDefinition.objects.get(name='last_name').order == 3
395 403
    assert AttributeDefinition.objects.get(name='prefered_color').order == 12
396 404

  
397 405
    # import empty json
398 406
    resp = app.get('/', status=200)
399 407
    resp = resp.click('Import')
400 408
    resp.form['parameters_json'] = Upload('export.json', b'{}', 'application/json')
401 409
    resp = resp.form.submit()
402
    assert Variable.objects.count() == 3
410
    assert Variable.objects.count() == 4
403 411
    assert AttributeDefinition.objects.count() == 12
404 412
    assert Variable.objects.get(name='foo').label == 'bar'
405 413
    assert AttributeDefinition.objects.get(name='title').description == 'genre'
406 414
    assert AttributeDefinition.objects.get(name='title').order == 1
407 415
    assert AttributeDefinition.objects.get(name='last_name').label == 'Nom de naissance'
408 416
    assert AttributeDefinition.objects.get(name='last_name').order == 3
409 417
    assert AttributeDefinition.objects.get(name='prefered_color').order == 12
410 418

  
......
414 422
    Variable.objects.create(name='foo2', value='bar2', service=combo).save()
415 423
    AttributeDefinition.objects.create(name='prefered_color', label='not empty').save()
416 424
    assert Variable.objects.count() == 1
417 425
    assert AttributeDefinition.objects.count() == 1
418 426
    resp = app.get('/', status=200)
419 427
    resp = resp.click('Import')
420 428
    resp.form['parameters_json'] = Upload('export.json', export_json.encode('utf-8'), 'application/json')
421 429
    resp = resp.form.submit()
422
    assert Variable.objects.count() == 2
430
    assert Variable.objects.count() == 3
423 431
    assert AttributeDefinition.objects.count() == 12
424 432
    assert Variable.objects.get(name='foo').label == 'bar'
425 433
    assert AttributeDefinition.objects.get(name='title').order == 4
426 434
    assert AttributeDefinition.objects.get(name='last_name').order == 2
427 435
    assert AttributeDefinition.objects.get(name='prefered_color').order == 1
428 436

  
429 437
    # import invalid json
430 438
    resp = app.get('/', status=200)
431 439
    resp = resp.click('Import')
432 440
    resp.form['parameters_json'] = Upload('export.json', b'garbage', 'application/json')
433 441
    resp = resp.form.submit()
434
    assert Variable.objects.count() == 2
442
    assert Variable.objects.count() == 3
435 443
    assert AttributeDefinition.objects.count() == 12
436 444

  
437 445
    # import corrupted json
438 446
    export['variables'][0]['label'] = 'foofoo'
439 447
    fields = export['profile']['fields']
440 448
    assert fields[2]['name'] == 'title'
441 449
    fields[2]['label'] = 'Nom de naissance'
442 450
    export_json = json.dumps(export)
443 451
    resp = app.get('/', status=200)
444 452
    resp = resp.click('Import')
445 453
    resp.form['parameters_json'] = Upload('export.json', export_json.encode('utf-8'), 'application/json')
446 454
    with pytest.raises(IntegrityError):
447 455
        resp = resp.form.submit()
448
    assert Variable.objects.count() == 2
456
    assert Variable.objects.count() == 3
449 457
    assert AttributeDefinition.objects.count() == 12
450 458
    assert Variable.objects.get(name='foo').label == 'bar'
451 459

  
452 460

  
453 461
def test_services_dict_templated_url(settings):
454 462
    settings.TEMPLATE_VARS = {'passerelle_url': 'http://example.com/'}
455 463
    variable = Variable.objects.create(name='sms_url', value='{{passerelle_url}}send/')
456 464
    Variable.objects.create(name='foo', value='bar')
457
-