0002-misc-add-export-import-API-60698.patch
tests/api/test_export_import.py | ||
---|---|---|
1 |
import io |
|
2 |
import json |
|
3 |
import os |
|
4 |
import tarfile |
|
5 |
import xml.etree.ElementTree as ET |
|
6 | ||
7 |
import pytest |
|
8 | ||
9 |
from wcs.blocks import BlockDef |
|
10 |
from wcs.categories import Category |
|
11 |
from wcs.data_sources import NamedDataSource |
|
12 |
from wcs.fields import BlockField, StringField |
|
13 |
from wcs.formdef import FormDef |
|
14 |
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef |
|
15 |
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef, WorkflowVariablesFieldsFormDef |
|
16 | ||
17 |
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app |
|
18 |
from .utils import sign_uri |
|
19 | ||
20 | ||
21 |
@pytest.fixture |
|
22 |
def pub(): |
|
23 |
pub = create_temporary_pub(sql_mode=True) |
|
24 |
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd: |
|
25 |
fd.write( |
|
26 |
'''\ |
|
27 |
[api-secrets] |
|
28 |
coucou = 1234 |
|
29 |
''' |
|
30 |
) |
|
31 | ||
32 |
Category.wipe() |
|
33 |
FormDef.wipe() |
|
34 |
BlockDef.wipe() |
|
35 |
Workflow.wipe() |
|
36 | ||
37 |
return pub |
|
38 | ||
39 | ||
40 |
def teardown_module(module): |
|
41 |
clean_temporary_pub() |
|
42 | ||
43 | ||
44 |
def test_export_import_index(pub): |
|
45 |
get_app(pub).get('/api/export-import/', status=403) |
|
46 |
resp = get_app(pub).get(sign_uri('/api/export-import/')) |
|
47 |
assert resp.json['data'][0]['id'] == 'forms' |
|
48 |
assert resp.json['data'][0]['text'] == 'Forms' |
|
49 |
assert resp.json['data'][0]['urls']['list'] == 'http://example.net/api/export-import/forms/' |
|
50 | ||
51 | ||
52 |
def test_export_import_list_forms(pub): |
|
53 |
resp = get_app(pub).get(sign_uri('/api/export-import/forms/')) |
|
54 |
assert not resp.json['data'] |
|
55 | ||
56 |
formdef = FormDef() |
|
57 |
formdef.name = 'Test' |
|
58 |
formdef.store() |
|
59 | ||
60 |
resp = get_app(pub).get(sign_uri('/api/export-import/forms/')) |
|
61 |
assert resp.json['data'][0]['id'] == 'test' |
|
62 |
assert resp.json['data'][0]['text'] == 'Test' |
|
63 | ||
64 | ||
65 |
def test_export_import_list_404(pub): |
|
66 |
get_app(pub).get(sign_uri('/api/export-import/xxx/'), status=404) |
|
67 | ||
68 | ||
69 |
def test_export_import_form(pub): |
|
70 |
formdef = FormDef() |
|
71 |
formdef.name = 'Test' |
|
72 |
formdef.store() |
|
73 | ||
74 |
resp = get_app(pub).get(sign_uri('/api/export-import/forms/')) |
|
75 |
resp = get_app(pub).get(sign_uri(resp.json['data'][0]['urls']['export'])) |
|
76 |
assert resp.text.startswith('<formdef ') |
|
77 | ||
78 | ||
79 |
def test_export_import_form_404(pub): |
|
80 |
get_app(pub).get(sign_uri('/api/export-import/xxx/plop/'), status=404) |
|
81 | ||
82 | ||
83 |
def test_export_import_dependencies(pub): |
|
84 |
formdef = FormDef() |
|
85 |
formdef.name = 'Test' |
|
86 |
formdef.store() |
|
87 | ||
88 |
resp = get_app(pub).get(sign_uri('/api/export-import/forms/')) |
|
89 |
resp = get_app(pub).get(sign_uri(resp.json['data'][0]['urls']['dependencies'])) |
|
90 |
assert not resp.json['data'] |
|
91 | ||
92 |
block = BlockDef(name='test') |
|
93 |
block.store() |
|
94 | ||
95 |
workflow = Workflow(name='test') |
|
96 |
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow) |
|
97 |
workflow.backoffice_fields_formdef.fields = [ |
|
98 |
BlockField(id='bo1', label='test', type='block:test'), |
|
99 |
] |
|
100 |
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow) |
|
101 |
workflow.variables_formdef.fields = [StringField(label='Test', id='1')] |
|
102 | ||
103 |
status = workflow.add_status('New') |
|
104 |
form = FormWorkflowStatusItem() |
|
105 |
form.parent = status |
|
106 |
status.items.append(form) |
|
107 | ||
108 |
data_source = NamedDataSource(name='foobar') |
|
109 |
data_source.store() |
|
110 | ||
111 |
display_form = FormWorkflowStatusItem() |
|
112 |
display_form.id = '_x' |
|
113 |
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form) |
|
114 |
display_form.formdef.fields.append(StringField(label='Test', data_source={'type': 'foobar'})) |
|
115 |
status.items.append(display_form) |
|
116 |
display_form.parent = status |
|
117 | ||
118 |
workflow.store() |
|
119 | ||
120 |
formdef.fields = [ |
|
121 |
BlockField(id='1', label='test', type='block:test'), |
|
122 |
] |
|
123 |
formdef.workflow = workflow |
|
124 |
formdef.store() |
|
125 | ||
126 |
resp = get_app(pub).get(sign_uri('/api/export-import/forms/')) |
|
127 |
resp = get_app(pub).get(sign_uri(resp.json['data'][0]['urls']['dependencies'])) |
|
128 |
assert resp.json['data'] |
|
129 |
assert {(x['id'], x['type']) for x in resp.json['data']} == {('test', 'workflows'), ('test', 'blocks')} |
|
130 | ||
131 |
resp = get_app(pub).get(sign_uri('/api/export-import/workflows/')) |
|
132 |
resp = get_app(pub).get(sign_uri(resp.json['data'][0]['urls']['dependencies'])) |
|
133 |
assert resp.json['data'] |
|
134 |
assert {(x['id'], x['type']) for x in resp.json['data']} == { |
|
135 |
('foobar', 'data-sources'), |
|
136 |
('test', 'blocks'), |
|
137 |
} |
|
138 | ||
139 | ||
140 |
def create_bundle(*args): |
|
141 |
tar_io = io.BytesIO() |
|
142 |
with tarfile.open(mode='w', fileobj=tar_io) as tar: |
|
143 |
manifest_json = { |
|
144 |
'application': 'Test', |
|
145 |
'slug': 'test', |
|
146 |
'description': '', |
|
147 |
'elements': [ |
|
148 |
{'type': 'forms', 'slug': 'test', 'name': 'test'}, |
|
149 |
{'type': 'blocks', 'slug': 'test', 'name': 'test'}, |
|
150 |
{'type': 'workflows', 'slug': 'test', 'name': 'test'}, |
|
151 |
{'type': 'forms-categories', 'slug': 'test', 'name': 'test'}, |
|
152 |
], |
|
153 |
} |
|
154 |
manifest_fd = io.BytesIO(json.dumps(manifest_json, indent=2).encode()) |
|
155 |
tarinfo = tarfile.TarInfo('manifest.json') |
|
156 |
tarinfo.size = len(manifest_fd.getvalue()) |
|
157 |
tar.addfile(tarinfo, fileobj=manifest_fd) |
|
158 | ||
159 |
for (path, obj) in args: |
|
160 |
tarinfo = tarfile.TarInfo(path) |
|
161 |
xml_export = ET.tostring(obj.export_to_xml(include_id=True)) |
|
162 |
tarinfo.size = len(xml_export) |
|
163 |
tar.addfile(tarinfo, fileobj=io.BytesIO(xml_export)) |
|
164 | ||
165 |
return tar_io.getvalue() |
|
166 | ||
167 | ||
168 |
def test_export_import_bundle_import(pub): |
|
169 |
workflow = Workflow(name='test') |
|
170 |
workflow.store() |
|
171 | ||
172 |
block = BlockDef(name='test') |
|
173 |
block.store() |
|
174 | ||
175 |
formdef = FormDef() |
|
176 |
formdef.name = 'Test' |
|
177 |
formdef.fields = [ |
|
178 |
BlockField(id='1', label='test', type='block:test'), |
|
179 |
] |
|
180 |
formdef.workflow = workflow |
|
181 |
formdef.disabled = False |
|
182 |
formdef.store() |
|
183 | ||
184 |
category = Category(name='Test') |
|
185 |
category.store() |
|
186 | ||
187 |
bundle = create_bundle( |
|
188 |
('forms/test', formdef), |
|
189 |
('blocks/test', block), |
|
190 |
('workflows/test', workflow), |
|
191 |
('forms-categories/test', category), |
|
192 |
) |
|
193 |
Category.wipe() |
|
194 |
FormDef.wipe() |
|
195 |
BlockDef.wipe() |
|
196 |
Workflow.wipe() |
|
197 | ||
198 |
resp = get_app(pub).put(sign_uri('/api/export-import/bundle-import/'), bundle) |
|
199 |
afterjob_url = resp.json['url'] |
|
200 |
resp = get_app(pub).put(sign_uri(afterjob_url)) |
|
201 |
assert resp.json['data']['status'] == 'completed' |
|
202 | ||
203 |
assert Category.count() == 1 |
|
204 |
assert FormDef.count() == 1 |
|
205 |
assert BlockDef.count() == 1 |
|
206 |
assert Workflow.count() == 1 |
|
207 |
assert FormDef.select()[0].fields[0].type == 'block:test' |
|
208 | ||
209 |
# run new import to check it doesn't duplicate objects |
|
210 |
resp = get_app(pub).put(sign_uri('/api/export-import/bundle-import/'), bundle) |
|
211 |
afterjob_url = resp.json['url'] |
|
212 |
resp = get_app(pub).put(sign_uri(afterjob_url)) |
|
213 |
assert resp.json['data']['status'] == 'completed' |
|
214 | ||
215 |
assert Category.count() == 1 |
|
216 |
assert FormDef.count() == 1 |
|
217 |
assert BlockDef.count() == 1 |
|
218 |
assert Workflow.count() == 1 |
|
219 | ||
220 |
# change immutable attribute and check it's not reset |
|
221 |
formdef = FormDef.select()[0] |
|
222 |
formdef.disabled = True |
|
223 |
formdef.store() |
|
224 | ||
225 |
resp = get_app(pub).put(sign_uri('/api/export-import/bundle-import/'), bundle) |
|
226 |
afterjob_url = resp.json['url'] |
|
227 |
resp = get_app(pub).put(sign_uri(afterjob_url)) |
|
228 |
assert resp.json['data']['status'] == 'completed' |
|
229 | ||
230 |
formdef = FormDef.select()[0] |
|
231 |
assert formdef.disabled is True |
wcs/api_export_import.py | ||
---|---|---|
1 |
# w.c.s. - web application for online forms |
|
2 |
# Copyright (C) 2005-2021 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or modify |
|
5 |
# it under the terms of the GNU General Public License as published by |
|
6 |
# the Free Software Foundation; either version 2 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 General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
import io |
|
18 |
import json |
|
19 |
import tarfile |
|
20 |
import xml.etree.ElementTree as ET |
|
21 | ||
22 |
from django.http import Http404, HttpResponse, HttpResponseForbidden, JsonResponse |
|
23 |
from django.urls import reverse |
|
24 | ||
25 |
from wcs.api_utils import is_url_signed |
|
26 |
from wcs.blocks import BlockDef |
|
27 |
from wcs.carddef import CardDef |
|
28 |
from wcs.categories import BlockCategory, CardDefCategory, Category, WorkflowCategory |
|
29 |
from wcs.data_sources import NamedDataSource, StubNamedDataSource |
|
30 |
from wcs.formdef import FormDef |
|
31 |
from wcs.mail_templates import MailTemplate |
|
32 |
from wcs.workflows import Workflow |
|
33 |
from wcs.wscalls import NamedWsCall |
|
34 | ||
35 |
from .qommon import _ |
|
36 |
from .qommon.afterjobs import AfterJob |
|
37 |
from .qommon.misc import indent_xml, xml_node_text |
|
38 | ||
39 |
klasses = { |
|
40 |
'blocks': BlockDef, |
|
41 |
'blocks-categories': BlockCategory, |
|
42 |
'cards': CardDef, |
|
43 |
'cards-categories': CardDefCategory, |
|
44 |
'data-sources': NamedDataSource, |
|
45 |
'forms-categories': Category, |
|
46 |
'forms': FormDef, |
|
47 |
'mail-templates': MailTemplate, |
|
48 |
'workflows-categories': WorkflowCategory, |
|
49 |
'workflows': Workflow, |
|
50 |
'wscalls': NamedWsCall, |
|
51 |
} |
|
52 | ||
53 |
klass_to_slug = {y: x for x, y in klasses.items()} |
|
54 | ||
55 | ||
56 |
def signature_required(func): |
|
57 |
def f(*args, **kwargs): |
|
58 |
if not is_url_signed(): |
|
59 |
return HttpResponseForbidden() |
|
60 |
return func(*args, **kwargs) |
|
61 | ||
62 |
return f |
|
63 | ||
64 | ||
65 |
@signature_required |
|
66 |
def index(request): |
|
67 |
response = [ |
|
68 |
{'id': 'forms', 'text': _('Forms'), 'singular': _('Form')}, |
|
69 |
{'id': 'cards', 'text': _('Cards'), 'singular': _('Card')}, |
|
70 |
{'id': 'workflows', 'text': _('Workflows'), 'singular': _('Workflow')}, |
|
71 |
{'id': 'blocks', 'text': _('Blocks'), 'singular': _('Block of fields'), 'minor': True}, |
|
72 |
{'id': 'data-sources', 'text': _('Data Sources'), 'singular': _('Data Source'), 'minor': True}, |
|
73 |
{'id': 'mail-templates', 'text': _('Mail Templates'), 'singular': _('Mail Template'), 'minor': True}, |
|
74 |
{'id': 'wscalls', 'text': _('Webservice Calls'), 'singular': _('Webservice Call'), 'minor': True}, |
|
75 |
{ |
|
76 |
'id': 'blocks-categories', |
|
77 |
'text': _('Categories (blocks)'), |
|
78 |
'singular': _('Category (block)'), |
|
79 |
'minor': True, |
|
80 |
}, |
|
81 |
{ |
|
82 |
'id': 'cards-categories', |
|
83 |
'text': _('Categories (cards)'), |
|
84 |
'singular': _('Category (cards)'), |
|
85 |
'minor': True, |
|
86 |
}, |
|
87 |
{ |
|
88 |
'id': 'forms-categories', |
|
89 |
'text': _('Categories (forms)'), |
|
90 |
'singular': _('Category (forms)'), |
|
91 |
'minor': True, |
|
92 |
}, |
|
93 |
{ |
|
94 |
'id': 'workflow-categories', |
|
95 |
'text': _('Categories (workflows)'), |
|
96 |
'singular': _('Category (workflows)'), |
|
97 |
'minor': True, |
|
98 |
}, |
|
99 |
] |
|
100 |
for obj in response: |
|
101 |
obj['urls'] = { |
|
102 |
'list': request.build_absolute_uri( |
|
103 |
reverse('api-export-import-objects-list', kwargs={'objects': obj['id']}) |
|
104 |
), |
|
105 |
} |
|
106 |
return JsonResponse({'data': response}) |
|
107 | ||
108 | ||
109 |
@signature_required |
|
110 |
def export_object_ref(request, obj): |
|
111 |
slug = obj.slug |
|
112 |
objects = klass_to_slug[obj.__class__] |
|
113 |
return { |
|
114 |
'id': slug, |
|
115 |
'text': obj.name, |
|
116 |
'type': objects, |
|
117 |
'urls': { |
|
118 |
'export': request.build_absolute_uri( |
|
119 |
reverse('api-export-import-object-export', kwargs={'objects': objects, 'slug': slug}) |
|
120 |
), |
|
121 |
'dependencies': request.build_absolute_uri( |
|
122 |
reverse('api-export-import-object-dependencies', kwargs={'objects': objects, 'slug': slug}) |
|
123 |
), |
|
124 |
}, |
|
125 |
} |
|
126 | ||
127 | ||
128 |
@signature_required |
|
129 |
def objects_list(request, objects): |
|
130 |
klass = klasses.get(objects) |
|
131 |
if not klass: |
|
132 |
raise Http404() |
|
133 |
return JsonResponse({'data': [export_object_ref(request, x) for x in klass.select()]}) |
|
134 | ||
135 | ||
136 |
def get_object(objects, slug): |
|
137 |
klass = klasses.get(objects) |
|
138 |
if not klass: |
|
139 |
raise Http404() |
|
140 |
return klass.get_by_slug(slug) |
|
141 | ||
142 | ||
143 |
@signature_required |
|
144 |
def object_export(request, objects, slug): |
|
145 |
obj = get_object(objects, slug) |
|
146 |
etree = obj.export_to_xml(include_id=True) |
|
147 |
indent_xml(etree) |
|
148 |
return HttpResponse(ET.tostring(etree), content_type='text/xml') |
|
149 | ||
150 | ||
151 |
@signature_required |
|
152 |
def object_dependencies(request, objects, slug): |
|
153 |
obj = get_object(objects, slug) |
|
154 |
dependencies = [] |
|
155 |
if hasattr(obj, 'get_dependencies'): |
|
156 |
for dependency in obj.get_dependencies(): |
|
157 |
if dependency is None or isinstance(dependency, StubNamedDataSource): |
|
158 |
continue |
|
159 |
dependencies.append(export_object_ref(request, dependency)) |
|
160 |
return JsonResponse({'data': dependencies}) |
|
161 | ||
162 | ||
163 |
class BundleImportJob(AfterJob): |
|
164 |
def __init__(self, tar_content, **kwargs): |
|
165 |
super().__init__(**kwargs) |
|
166 |
self.tar_content = tar_content |
|
167 | ||
168 |
def execute(self): |
|
169 |
tar_io = io.BytesIO(self.tar_content) |
|
170 |
with tarfile.open(fileobj=tar_io) as self.tar: |
|
171 |
manifest = json.loads(self.tar.extractfile('manifest.json').read().decode()) |
|
172 |
self.app_name = manifest.get('application') |
|
173 | ||
174 |
# first pass on formdef/carddef/blockdef/workflows to create them empty |
|
175 |
# (name and slug); so they can be found for sure in import pass |
|
176 |
for type in ('forms', 'cards', 'blocks', 'workflows'): |
|
177 |
self.pre_install([x for x in manifest.get('elements') if x.get('type') == type]) |
|
178 | ||
179 |
# real installation pass |
|
180 |
for type in ( |
|
181 |
'blocks-categories', |
|
182 |
'cards-categories', |
|
183 |
'forms-categories', |
|
184 |
'workflows-categories', |
|
185 |
'data-sources', |
|
186 |
'wscalls', |
|
187 |
'mail-templates', |
|
188 |
'forms', |
|
189 |
'cards', |
|
190 |
'blocks', |
|
191 |
'workflows', |
|
192 |
): |
|
193 |
self.install([x for x in manifest.get('elements') if x.get('type') == type]) |
|
194 | ||
195 |
def pre_install(self, elements): |
|
196 |
for element in elements: |
|
197 |
element_klass = klasses[element['type']] |
|
198 |
element_content = self.tar.extractfile('%s/%s' % (element['type'], element['slug'])).read() |
|
199 |
tree = ET.fromstring(element_content) |
|
200 |
if hasattr(element_klass, 'url_name'): |
|
201 |
slug = xml_node_text(tree.find('url_name')) |
|
202 |
else: |
|
203 |
slug = xml_node_text(tree.find('slug')) |
|
204 |
try: |
|
205 |
existing_object = element_klass.get_by_slug(slug) |
|
206 |
except KeyError: |
|
207 |
pass |
|
208 |
else: |
|
209 |
if existing_object: |
|
210 |
continue |
|
211 |
new_object = element_klass() |
|
212 |
new_object.slug = slug |
|
213 |
new_object.name = '[pre-import] %s' % xml_node_text(tree.find('name')) |
|
214 |
new_object.store(comment=_('Application (%s)') % self.app_name) |
|
215 | ||
216 |
def install(self, elements): |
|
217 |
for element in elements: |
|
218 |
element_klass = klasses[element['type']] |
|
219 |
element_content = self.tar.extractfile('%s/%s' % (element['type'], element['slug'])).read() |
|
220 |
new_object = element_klass.import_from_xml_tree( |
|
221 |
ET.fromstring(element_content), include_id=False, check_datasources=False |
|
222 |
) |
|
223 |
try: |
|
224 |
existing_object = element_klass.get_by_slug(new_object.slug) |
|
225 |
if existing_object is None: |
|
226 |
raise KeyError() |
|
227 |
except KeyError: |
|
228 |
new_object.store(comment=_('Application (%s)') % self.app_name) |
|
229 |
continue |
|
230 |
# replace |
|
231 |
new_object.id = existing_object.id |
|
232 |
if element['type'] in ('forms', 'cards'): |
|
233 |
# keep some settings |
|
234 |
for attr in ( |
|
235 |
'workflow_options', |
|
236 |
'workflow_roles', |
|
237 |
'roles', |
|
238 |
'required_authentication_contexts', |
|
239 |
'backoffice_submission_roles', |
|
240 |
'publication_date', |
|
241 |
'expiration_date', |
|
242 |
'disabled', |
|
243 |
): |
|
244 |
setattr(new_object, attr, getattr(existing_object, attr)) |
|
245 |
new_object.store(comment=_('Application (%s) update') % self.app_name) |
|
246 | ||
247 | ||
248 |
@signature_required |
|
249 |
def bundle_import(request): |
|
250 |
job = BundleImportJob(tar_content=request.body) |
|
251 |
job.store() |
|
252 |
job.run(spool=True) |
|
253 |
return JsonResponse({'err': 0, 'url': job.get_api_status_url()}) |
wcs/blocks.py | ||
---|---|---|
110 | 110 |
) |
111 | 111 |
return Template(self.digest_template, autoescape=False).render(context) |
112 | 112 | |
113 |
def get_dependencies(self): |
|
114 |
yield self.category |
|
115 |
for field in self.fields or []: |
|
116 |
yield from field.get_dependencies() |
|
117 | ||
113 | 118 |
def export_to_xml(self, include_id=False): |
114 | 119 |
root = ET.Element(self.xml_root_node) |
115 | 120 |
if include_id and self.id: |
wcs/compat.py | ||
---|---|---|
134 | 134 |
upload.fp = upload_file.file |
135 | 135 |
self.form[k] = upload |
136 | 136 | |
137 |
def build_absolute_uri(self): |
|
138 |
return self.django_request.build_absolute_uri() |
|
137 |
def build_absolute_uri(self, *args):
|
|
138 |
return self.django_request.build_absolute_uri(*args)
|
|
139 | 139 | |
140 | 140 | |
141 | 141 |
class CompatWcsPublisher(WcsPublisher): |
wcs/fields.py | ||
---|---|---|
659 | 659 |
elif self.store_structured_value and '%s_structured' % self.id in data: |
660 | 660 |
del data['%s_structured' % self.id] |
661 | 661 | |
662 |
def get_dependencies(self): |
|
663 |
if getattr(self, 'data_source', None): |
|
664 |
data_source_type = self.data_source.get('type') |
|
665 |
if data_source_type and data_source_type.startswith('carddef:'): |
|
666 |
from .carddef import CardDef |
|
667 | ||
668 |
carddef_slug = data_source_type.split(':')[1] |
|
669 |
try: |
|
670 |
yield CardDef.get_by_urlname(carddef_slug) |
|
671 |
except KeyError: |
|
672 |
pass |
|
673 |
else: |
|
674 |
from .data_sources import NamedDataSource |
|
675 | ||
676 |
yield NamedDataSource.get_by_slug(data_source_type, ignore_errors=True) |
|
677 | ||
662 | 678 |
def __repr__(self): |
663 | 679 |
return '<%s %s %r>' % (self.__class__.__name__, self.id, self.label and self.label[:64]) |
664 | 680 | |
... | ... | |
3425 | 3441 |
def get_type_label(self): |
3426 | 3442 |
return _('Field Block (%s)') % self.block.name |
3427 | 3443 | |
3444 |
def get_dependencies(self): |
|
3445 |
yield self.block |
|
3446 | ||
3428 | 3447 |
def fill_admin_form(self, form): |
3429 | 3448 |
super().fill_admin_form(form) |
3430 | 3449 |
if form.get_widget('prefill'): |
wcs/formdef.py | ||
---|---|---|
671 | 671 | |
672 | 672 |
workflow = property(get_workflow, set_workflow) |
673 | 673 | |
674 |
def get_dependencies(self): |
|
675 |
yield self.category |
|
676 |
if self.workflow_id: |
|
677 |
yield self.workflow |
|
678 |
for field in self.fields or []: |
|
679 |
yield from field.get_dependencies() |
|
680 | ||
674 | 681 |
@property |
675 | 682 |
def keywords_list(self): |
676 | 683 |
if not self.keywords: |
wcs/qommon/afterjobs.py | ||
---|---|---|
19 | 19 |
import traceback |
20 | 20 |
import uuid |
21 | 21 | |
22 |
from quixote import get_publisher, get_response |
|
22 |
from quixote import get_publisher, get_request, get_response
|
|
23 | 23 |
from quixote.directory import Directory |
24 | 24 | |
25 | 25 |
from . import N_, _, errors, force_text |
... | ... | |
135 | 135 |
return obj_dict |
136 | 136 |
return self.__dict__ |
137 | 137 | |
138 |
def get_api_status_url(self): |
|
139 |
return get_request().build_absolute_uri('/api/jobs/%s/' % self.id) |
|
140 | ||
138 | 141 |
def get_processing_url(self): |
139 | 142 |
return '/backoffice/processing?job=%s' % self.id |
wcs/urls.py | ||
---|---|---|
16 | 16 | |
17 | 17 |
from django.conf.urls import url |
18 | 18 | |
19 |
from . import api, compat, views |
|
19 |
from . import api, api_export_import, compat, views
|
|
20 | 20 |
from .statistics import views as statistics_views |
21 | 21 | |
22 | 22 |
urlpatterns = [ |
... | ... | |
24 | 24 |
url(r'^i18n\.js$', views.i18n_js), |
25 | 25 |
url(r'^backoffice/', views.backoffice), |
26 | 26 |
url(r'^__provision__/$', api.provisionning), |
27 |
url(r'^api/export-import/$', api_export_import.index, name='api-export-import'), |
|
28 |
url(r'^api/export-import/bundle-import/$', api_export_import.bundle_import), |
|
29 |
url( |
|
30 |
r'^api/export-import/(?P<objects>[\w-]+)/$', |
|
31 |
api_export_import.objects_list, |
|
32 |
name='api-export-import-objects-list', |
|
33 |
), |
|
34 |
url( |
|
35 |
r'^api/export-import/(?P<objects>[\w-]+)/(?P<slug>[\w_-]+)/$', |
|
36 |
api_export_import.object_export, |
|
37 |
name='api-export-import-object-export', |
|
38 |
), |
|
39 |
url( |
|
40 |
r'^api/export-import/(?P<objects>[\w-]+)/(?P<slug>[\w_-]+)/dependencies/$', |
|
41 |
api_export_import.object_dependencies, |
|
42 |
name='api-export-import-object-dependencies', |
|
43 |
), |
|
27 | 44 |
url(r'^api/validate-condition$', api.validate_condition, name='api-validate-condition'), |
28 | 45 |
url(r'^api/validate-expression$', api.validate_expression, name='api-validate-expression'), |
29 | 46 |
url(r'^api/reverse-geocoding$', api.reverse_geocoding, name='api-reverse-geocoding'), |
wcs/wf/form.py | ||
---|---|---|
167 | 167 |
changed |= field.migrate() |
168 | 168 |
return changed |
169 | 169 | |
170 |
def get_dependencies(self): |
|
171 |
if self.formdef and self.formdef.fields: |
|
172 |
for field in self.formdef.fields: |
|
173 |
yield from field.get_dependencies() |
|
174 | ||
170 | 175 |
def export_to_xml(self, charset, include_id=False): |
171 | 176 |
item = WorkflowStatusItem.export_to_xml(self, charset, include_id=include_id) |
172 | 177 |
if not hasattr(self, 'formdef') or not self.formdef or not self.formdef.fields: |
wcs/workflows.py | ||
---|---|---|
610 | 610 |
base_url = get_publisher().get_backoffice_url() |
611 | 611 |
return '%s/workflows/%s/' % (base_url, self.id) |
612 | 612 | |
613 |
def get_dependencies(self): |
|
614 |
yield self.category |
|
615 |
if self.variables_formdef and self.variables_formdef.fields: |
|
616 |
for field in self.variables_formdef.fields: |
|
617 |
yield from field.get_dependencies() |
|
618 |
if self.backoffice_fields_formdef and self.backoffice_fields_formdef.fields: |
|
619 |
for field in self.backoffice_fields_formdef.fields: |
|
620 |
yield from field.get_dependencies() |
|
621 |
if self.possible_status: |
|
622 |
for status in self.possible_status: |
|
623 |
yield from status.get_dependencies() |
|
624 | ||
613 | 625 |
@classmethod |
614 | 626 |
def get(cls, id, ignore_errors=False, ignore_migration=False): |
615 | 627 |
if id == '_default': |
... | ... | |
1893 | 1905 |
def get_admin_url(self): |
1894 | 1906 |
return self.parent.get_admin_url() + 'status/%s/' % self.id |
1895 | 1907 | |
1908 |
def get_dependencies(self): |
|
1909 |
for action in self.items or []: |
|
1910 |
yield from action.get_dependencies() |
|
1911 | ||
1896 | 1912 |
def evaluate_live_form(self, form, filled, user): |
1897 | 1913 |
for item in self.get_active_items(form, filled, user): |
1898 | 1914 |
item.evaluate_live_form(form, filled, user) |
... | ... | |
2185 | 2201 |
def get_add_role_label(self): |
2186 | 2202 |
return self.parent.parent.get_add_role_label() |
2187 | 2203 | |
2204 |
def get_dependencies(self): |
|
2205 |
return [] |
|
2206 | ||
2188 | 2207 |
@noop_mark |
2189 | 2208 |
def perform(self, formdata): |
2190 | 2209 |
pass |
2191 |
- |