0004-import_site-add-clean-if-empty-and-overwrite-options.patch
passerelle/apps/csvdatasource/models.py | ||
---|---|---|
383 | 383 |
return d |
384 | 384 | |
385 | 385 |
@classmethod |
386 |
def import_json_real(cls, d, **kwargs): |
|
386 |
def import_json_real(cls, overwrite, instance, d, **kwargs):
|
|
387 | 387 |
queries = d.pop('queries', []) |
388 |
instance = super(CsvDataSource, cls).import_json_real(d, **kwargs) |
|
388 |
instance = super(CsvDataSource, cls).import_json_real(overwrite, instance, d, **kwargs)
|
|
389 | 389 |
new = [] |
390 |
if instance and overwrite: |
|
391 |
Query.objects.filter(resource=instance).delete() |
|
390 | 392 |
for query in queries: |
391 | 393 |
q = Query.import_json(query) |
392 | 394 |
q.resource = instance |
passerelle/base/management/commands/import_site.py | ||
---|---|---|
3 | 3 | |
4 | 4 |
from django.core.management.base import BaseCommand |
5 | 5 | |
6 |
from passerelle.base.models import ApiUser, BaseResource |
|
6 | 7 |
from passerelle.utils import import_site |
7 | 8 | |
8 | 9 | |
... | ... | |
10 | 11 |
args = '<filename>' |
11 | 12 |
help = 'Import an exported site' |
12 | 13 |
option_list = BaseCommand.option_list + ( |
14 |
make_option('--clean', action='store_true', default=False, |
|
15 |
help='Clean site before importing'), |
|
13 | 16 |
make_option('--import-users', action='store_true', default=False, |
14 | 17 |
help='Import users and access rights'), |
18 |
make_option('--if-empty', action='store_true', default=False, |
|
19 |
help='Import only if passerelle is empty'), |
|
20 |
make_option('--overwrite', action='store_true', default=False, |
|
21 |
help='Overwirte existing resources'), |
|
15 | 22 |
) |
16 | 23 | |
17 | 24 |
def handle(self, filename, **options): |
18 |
import_site(json.load(open(filename)), import_users=options['import_users']) |
|
25 |
import_site(json.load(open(filename)), |
|
26 |
if_empty=options['if_empty'], |
|
27 |
clean=options['clean'], |
|
28 |
overwrite=options['overwrite'], |
|
29 |
import_users=options['import_users']) |
passerelle/base/models.py | ||
---|---|---|
62 | 62 |
} |
63 | 63 | |
64 | 64 |
@classmethod |
65 |
def import_json(self, d): |
|
65 |
def import_json(self, d, overwrite=False):
|
|
66 | 66 |
if d.get('@type') != 'passerelle-user': |
67 | 67 |
raise ValueError('not a passerelle user export') |
68 | 68 |
d = d.copy() |
69 | 69 |
d.pop('@type') |
70 |
return self.objects.get_or_create(username=d['username'], |
|
71 |
defaults=d) |
|
70 |
api_user, created = self.objects.get_or_create(username=d['username'], defaults=d) |
|
71 |
if overwrite and not created: |
|
72 |
for key in d: |
|
73 |
setattr(api_user, key, d[key]) |
|
74 |
api_user.save() |
|
72 | 75 | |
73 | 76 | |
74 | 77 |
class TemplateVar(models.Model): |
... | ... | |
219 | 222 |
return d |
220 | 223 | |
221 | 224 |
@staticmethod |
222 |
def import_json(d, import_users=False): |
|
225 |
def import_json(d, import_users=False, overwrite=False):
|
|
223 | 226 |
if d.get('@type') != 'passerelle-resource': |
224 | 227 |
raise ValueError('not a passerelle resource export') |
225 | 228 | |
... | ... | |
228 | 231 |
app_label, model_name = d['resource_type'].split('.') |
229 | 232 |
model = apps.get_model(app_label, model_name) |
230 | 233 |
try: |
231 |
return model.objects.get(slug=d['slug']) |
|
234 |
instance = model.objects.get(slug=d['slug']) |
|
235 |
if not overwrite: |
|
236 |
return |
|
232 | 237 |
except model.DoesNotExist: |
233 |
pass
|
|
238 |
instance = None
|
|
234 | 239 |
with transaction.atomic(): |
235 | 240 |
# prevent semi-creation of ressources |
236 |
instance = model.import_json_real(d) |
|
241 |
instance = model.import_json_real(overwrite, instance, d)
|
|
237 | 242 |
resource_type = ContentType.objects.get_for_model(instance) |
238 | 243 |
# We can only connect AccessRight objects to the new Resource after its creation |
239 | 244 |
if import_users: |
... | ... | |
247 | 252 |
return instance |
248 | 253 | |
249 | 254 |
@classmethod |
250 |
def import_json_real(cls, d, **kwargs): |
|
255 |
def import_json_real(cls, overwrite, instance, d, **kwargs):
|
|
251 | 256 |
init_kwargs = { |
252 | 257 |
'title': d['title'], |
253 | 258 |
'slug': d['slug'], |
... | ... | |
255 | 260 |
'log_level': d['log_level'], |
256 | 261 |
} |
257 | 262 |
init_kwargs.update(kwargs) |
258 |
instance = cls(**init_kwargs) |
|
263 |
if instance: |
|
264 |
for key in init_kwargs: |
|
265 |
setattr(instance, key, init_kwargs[key]) |
|
266 |
else: |
|
267 |
instance = cls(**init_kwargs) |
|
259 | 268 |
for field, model in cls._meta.get_concrete_fields_with_model(): |
260 | 269 |
if field.name == 'id': |
261 | 270 |
continue |
passerelle/utils/__init__.py | ||
---|---|---|
192 | 192 |
return d |
193 | 193 | |
194 | 194 | |
195 |
def import_site(d, import_users=False): |
|
195 |
def import_site(d, if_empty=False, clean=False, overwrite=False, import_users=False):
|
|
196 | 196 |
'''Load passerelle configuration (users, resources and ACLs) from a dictionnary loaded from |
197 | 197 |
JSON |
198 | 198 |
''' |
199 | 199 |
d = d.copy() |
200 | 200 | |
201 |
def is_empty(): |
|
202 |
if import_users: |
|
203 |
if ApiUser.objects.count(): |
|
204 |
return False |
|
205 | ||
206 |
for subclass in BaseResource.__subclasses__(): |
|
207 |
if subclass._meta.abstract: |
|
208 |
continue |
|
209 |
if subclass.objects.count(): |
|
210 |
return False |
|
211 |
return True |
|
212 | ||
213 |
if if_empty and not is_empty(): |
|
214 |
return |
|
215 | ||
216 |
if clean: |
|
217 |
for subclass in BaseResource.__subclasses__(): |
|
218 |
if subclass._meta.abstract: |
|
219 |
continue |
|
220 |
subclass.objects.all().delete() |
|
221 |
if import_users: |
|
222 |
ApiUser.objects.all().delete() |
|
223 | ||
201 | 224 |
with transaction.atomic(): |
202 | 225 |
if import_users: |
203 | 226 |
for apiuser in d['apiusers']: |
204 |
ApiUser.import_json(apiuser) |
|
227 |
ApiUser.import_json(apiuser, overwrite=overwrite)
|
|
205 | 228 | |
206 | 229 |
for resource in d['resources']: |
207 |
BaseResource.import_json(resource, import_users=import_users) |
|
230 |
BaseResource.import_json(resource, overwrite=overwrite, import_users=import_users) |
tests/test_import_export.py | ||
---|---|---|
87 | 87 |
return request.param |
88 | 88 | |
89 | 89 | |
90 |
def get_output_of_command(command, *args, **kwargs): |
|
91 |
old_stdout = sys.stdout |
|
92 |
output = sys.stdout = StringIO() |
|
93 |
call_command(command, *args, **kwargs) |
|
94 |
sys.stdout = old_stdout |
|
95 |
return output.getvalue() |
|
96 | ||
97 | ||
90 | 98 |
def test_export_csvdatasource(app, setup, filetype): |
91 | 99 |
def clear(): |
92 | 100 |
Query.objects.all().delete() |
... | ... | |
109 | 117 |
second['resources'][0]['csv_file']['name'] = 'whocares' |
110 | 118 |
assert first == second |
111 | 119 | |
112 |
old_stdout = sys.stdout |
|
113 |
output = sys.stdout = StringIO() |
|
114 |
call_command('export_site') |
|
115 |
sys.stdout = old_stdout |
|
116 | ||
117 |
output = output.getvalue() |
|
120 |
output = get_output_of_command('export_site') |
|
118 | 121 |
third = json.loads(output) |
119 | 122 |
third['resources'][0]['csv_file']['name'] = 'whocares' |
120 | 123 |
assert first == third |
... | ... | |
127 | 130 |
fourth = export_site() |
128 | 131 |
fourth['resources'][0]['csv_file']['name'] = 'whocares' |
129 | 132 |
assert first == fourth |
133 | ||
134 |
Query.objects.all().delete() |
|
135 | ||
136 |
with tempfile.NamedTemporaryFile() as f: |
|
137 |
f.write(output) |
|
138 |
f.flush() |
|
139 |
call_command('import_site', f.name, import_users=True) |
|
140 |
assert Query.objects.count() == 0 |
|
141 | ||
142 |
with tempfile.NamedTemporaryFile() as f: |
|
143 |
f.write(output) |
|
144 |
f.flush() |
|
145 |
call_command('import_site', f.name, overwrite=True, import_users=True) |
|
146 |
assert Query.objects.count() == 1 |
|
147 | ||
148 |
query = Query(slug='query-2_', resource=CsvDataSource.objects.get(), structure='array') |
|
149 |
query.projections = '\n'.join(['id:int(id)', 'prenom:prenom']) |
|
150 |
query.save() |
|
151 | ||
152 |
assert Query.objects.count() == 2 |
|
153 | ||
154 |
with tempfile.NamedTemporaryFile() as f: |
|
155 |
f.write(output) |
|
156 |
f.flush() |
|
157 |
call_command('import_site', f.name, clean=True, overwrite=True, import_users=True) |
|
158 |
assert Query.objects.count() == 1 |
|
159 |
assert Query.objects.filter(slug='query-1_').exists() |
|
130 |
- |