Projet

Général

Profil

0001-manage-resource-from-command-line-fixes-26582.patch

Benjamin Dauvergne, 25 septembre 2018 17:09

Télécharger (9,36 ko)

Voir les différences:

Subject: [PATCH] manage resource from command line (fixes #26582)

 .../base/management/commands/resource.py      | 189 ++++++++++++++++++
 passerelle/forms.py                           |  17 +-
 2 files changed, 202 insertions(+), 4 deletions(-)
 create mode 100644 passerelle/base/management/commands/resource.py
passerelle/base/management/commands/resource.py
1
# passerelle - uniform access to multiple data sources and services
2
# Copyright (C) 2017  Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from __future__ import print_function
18
import os
19
import argparse
20

  
21
from django.core.files import File
22
from django.core.management.base import BaseCommand, CommandError
23
from django.apps import apps
24
from django import forms
25
from django.forms.models import modelform_factory
26

  
27
from passerelle.base.models import BaseResource
28
from passerelle.forms import GenericConnectorForm
29

  
30

  
31
class Command(BaseCommand):
32
    help = 'manage resources'
33

  
34
    def add_arguments(self, parser):
35
        subparsers = parser.add_subparsers(parser_class=argparse.ArgumentParser)
36

  
37
        new_parser = subparsers.add_parser('list-type')
38
        new_parser.add_argument('--resource-type')
39
        new_parser.set_defaults(subcommand=self.list_type)
40

  
41
        new_parser = subparsers.add_parser('list')
42
        new_parser.add_argument('resource_type')
43
        new_parser.set_defaults(subcommand=self.list)
44

  
45
        new_parser = subparsers.add_parser('new')
46
        new_parser.add_argument('resource_type')
47
        new_parser.add_argument('--string-field',
48
                                nargs=2,
49
                                action='append',
50
                                default=[],
51
                                type=str)
52
        new_parser.add_argument('--file-field',
53
                                nargs=2,
54
                                action='append',
55
                                default=[],
56
                                type=str)
57
        new_parser.set_defaults(subcommand=self.new)
58

  
59
        new_parser = subparsers.add_parser('update')
60
        new_parser.add_argument('resource_type')
61
        new_parser.add_argument('slug')
62
        new_parser.add_argument('--string-field',
63
                                nargs=2,
64
                                action='append',
65
                                default=[],
66
                                type=str)
67
        new_parser.add_argument('--file-field',
68
                                nargs=2,
69
                                action='append',
70
                                default=[],
71
                                type=str)
72
        new_parser.set_defaults(subcommand=self.update)
73

  
74
        new_parser = subparsers.add_parser('delete')
75
        new_parser.add_argument('resource_type')
76
        new_parser.add_argument('slug')
77
        new_parser.set_defaults(subcommand=self.delete)
78

  
79
    def get_models(self):
80
        for app_config in apps.get_app_configs():
81
            for model in app_config.get_models():
82
                if issubclass(model, BaseResource):
83
                    yield app_config, model
84

  
85
    def get_model(self, resource_type):
86
        for app_config, model in self.get_models():
87
            if model._meta.label_lower == resource_type:
88
                return app_config, model
89
        raise CommandError('unknown resource_type %s' % resource_type)
90

  
91
    def get_form_class(self, app_config, model, fields=None):
92
        if hasattr(app_config, 'get_form_class'):
93
            form_class = app_config.get_form_class()
94
        else:
95
            form_class = modelform_factory(
96
                model,
97
                form=GenericConnectorForm,
98
                fields=fields,
99
                exclude=('slug', 'users'))
100
        return form_class
101

  
102
    def get_fields(self, options):
103
        for key, value in options.get('string_field', []):
104
            yield key
105
        for key, value in options.get('file_field', []):
106
            yield key
107

  
108
    def get_model_and_form_class(self, options):
109
        app_config, model = self.get_model(options['resource_type'])
110
        fields = list(self.get_fields(options))
111
        form_class = self.get_form_class(app_config, model, fields=fields)
112
        return model, form_class
113

  
114
    def list_type(self, **options):
115
        models = self.get_models()
116
        resource_type = options.get('resource_type')
117
        if resource_type:
118
            models = [self.get_model(resource_type)]
119
        for app_config, model in models:
120
            if not resource_type:
121
                print('-', model._meta.label_lower)
122
            form_class = self.get_form_class(app_config, model)
123
            for key in form_class.base_fields:
124
                field = form_class.base_fields[key]
125
                print('  -', key)
126
                print('   ', 'type:', 'file' if isinstance(field, forms.FileField) else 'string')
127
                if hasattr(field, 'choices') and field.choices:
128
                    print('   ', 'choices:')
129
                    for a, b in field.choices:
130
                        print('     %s: %s' % (a, b))
131
                if field.help_text:
132
                    print('   ', 'help text:', field.help_text)
133

  
134
    def list(self, **options):
135
        model, form_class = self.get_model_and_form_class(options)
136
        for instance in model.objects.all():
137
            for field in model._meta.get_fields():
138
                try:
139
                    attribute = field.attname
140
                except AttributeError:
141
                    continue
142
                value = getattr(instance, attribute)
143
                if field.is_relation:
144
                    value = list(value.all())
145
                print('%-20s: %s' % (field.name, value))
146

  
147
    def new(self, **options):
148
        model, form_class = self.get_model_and_form_class(options)
149
        self.do_form(form_class, options)
150

  
151
    def update(self, **options):
152
        model, form_class = self.get_model_and_form_class(options)
153
        try:
154
            instance = model.objects.get(slug=options['slug'])
155
        except model.DoesNotExist:
156
            raise CommandError('object %s with slug %s does not exist' % (options['resource_type'], options['slug']))
157
        self.do_form(form_class, options, instance=instance)
158

  
159
    def do_form(self, form_class, options, **kwargs):
160
        data = {}
161
        files = {}
162
        for key, value in options['string_field']:
163
            data[key] = value
164
        for key, value in options['file_field']:
165
            files[key] = File(open(value), name=os.path.basename(value))
166
        form = form_class(data, files, **kwargs)
167
        if not form.is_valid():
168
            for msg in form.errors.get('__all__', []):
169
                print('ERROR:', msg)
170
            for key in form.errors:
171
                if key == '__all__':
172
                    continue
173
                for msg in form.errors[key]:
174
                    print('ERROR:', key, ';', msg)
175
            raise CommandError('could not create %s' % options['resource_type'])
176
        form.save()
177

  
178
    def handle(self, *args, **options):
179
        method = options.get('subcommand')
180
        if method:
181
            method(**options)
182

  
183
    def delete(self, **options):
184
        model, form_class = self.get_model_and_form_class(options)
185
        try:
186
            instance = model.objects.get(slug=options['slug'])
187
        except model.DoesNotExist:
188
            raise CommandError('object %s with slug %s does not exist' % (options['resource_type'], options['slug']))
189
        instance.delete()
passerelle/forms.py
17 17
from django.utils.text import slugify
18 18
from django import forms
19 19

  
20

  
20 21
class GenericConnectorForm(forms.ModelForm):
21
    def save(self, commit=True):
22
        if not self.instance.slug:
23
            self.instance.slug = slugify(self.instance.title)
24
        return super(GenericConnectorForm, self).save(commit=commit)
22
    def clean(self):
23
        super(GenericConnectorForm, self).clean()
24
        title = self.cleaned_data.get('title') or self.instance.title
25
        if not self.instance.slug and title:
26
            self.instance.slug = slugify(title)
27
        exclude = self._get_validation_exclusions()
28
        exclude.remove('slug')
29
        try:
30
            self.instance.validate_unique(exclude=exclude)
31
        except forms.ValidationError:
32
            raise forms.ValidationError('generated slug is not unique')
33

  
25
-