mirror of
https://github.com/ansible/awx.git
synced 2026-03-21 10:57:36 -02:30
add api for testing credential plugins
This commit is contained in:
@@ -13,6 +13,7 @@ from awx.api.views import (
|
|||||||
CredentialOwnerTeamsList,
|
CredentialOwnerTeamsList,
|
||||||
CredentialCopy,
|
CredentialCopy,
|
||||||
CredentialInputSourceSubList,
|
CredentialInputSourceSubList,
|
||||||
|
CredentialExternalTest,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ urls = [
|
|||||||
url(r'^(?P<pk>[0-9]+)/owner_teams/$', CredentialOwnerTeamsList.as_view(), name='credential_owner_teams_list'),
|
url(r'^(?P<pk>[0-9]+)/owner_teams/$', CredentialOwnerTeamsList.as_view(), name='credential_owner_teams_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/copy/$', CredentialCopy.as_view(), name='credential_copy'),
|
url(r'^(?P<pk>[0-9]+)/copy/$', CredentialCopy.as_view(), name='credential_copy'),
|
||||||
url(r'^(?P<pk>[0-9]+)/input_sources/$', CredentialInputSourceSubList.as_view(), name='credential_input_source_sublist'),
|
url(r'^(?P<pk>[0-9]+)/input_sources/$', CredentialInputSourceSubList.as_view(), name='credential_input_source_sublist'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/test/$', CredentialExternalTest.as_view(), name='credential_external_test'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from awx.api.views import (
|
|||||||
CredentialTypeDetail,
|
CredentialTypeDetail,
|
||||||
CredentialTypeCredentialList,
|
CredentialTypeCredentialList,
|
||||||
CredentialTypeActivityStreamList,
|
CredentialTypeActivityStreamList,
|
||||||
|
CredentialTypeExternalTest,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ urls = [
|
|||||||
url(r'^(?P<pk>[0-9]+)/$', CredentialTypeDetail.as_view(), name='credential_type_detail'),
|
url(r'^(?P<pk>[0-9]+)/$', CredentialTypeDetail.as_view(), name='credential_type_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', CredentialTypeCredentialList.as_view(), name='credential_type_credential_list'),
|
url(r'^(?P<pk>[0-9]+)/credentials/$', CredentialTypeCredentialList.as_view(), name='credential_type_credential_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialTypeActivityStreamList.as_view(), name='credential_type_activity_stream_list'),
|
url(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialTypeActivityStreamList.as_view(), name='credential_type_activity_stream_list'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/test/$', CredentialTypeExternalTest.as_view(), name='credential_type_external_test'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1419,6 +1419,32 @@ class CredentialCopy(CopyAPIView):
|
|||||||
copy_return_serializer_class = serializers.CredentialSerializer
|
copy_return_serializer_class = serializers.CredentialSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class CredentialExternalTest(SubDetailAPIView):
|
||||||
|
"""
|
||||||
|
Test updates to the input values of an external credential before
|
||||||
|
saving them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
view_name = _('External Credential Test')
|
||||||
|
|
||||||
|
model = models.Credential
|
||||||
|
serializer_class = serializers.EmptySerializer
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
test_inputs = {}
|
||||||
|
for field_name, value in request.data.get('inputs', {}).items():
|
||||||
|
if value == '$encrypted$':
|
||||||
|
test_inputs[field_name] = obj.get_input(field_name)
|
||||||
|
else:
|
||||||
|
test_inputs[field_name] = value
|
||||||
|
try:
|
||||||
|
obj.credential_type.plugin.backend(None, **test_inputs)
|
||||||
|
return Response({}, status=status.HTTP_202_ACCEPTED)
|
||||||
|
except Exception as exc:
|
||||||
|
return Response({'inputs': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
class CredentialInputSourceDetail(RetrieveUpdateDestroyAPIView):
|
class CredentialInputSourceDetail(RetrieveUpdateDestroyAPIView):
|
||||||
|
|
||||||
view_name = _("Credential Input Source Detail")
|
view_name = _("Credential Input Source Detail")
|
||||||
@@ -1446,6 +1472,27 @@ class CredentialInputSourceSubList(SubListCreateAttachDetachAPIView):
|
|||||||
parent_key = 'target_credential'
|
parent_key = 'target_credential'
|
||||||
|
|
||||||
|
|
||||||
|
class CredentialTypeExternalTest(SubDetailAPIView):
|
||||||
|
"""
|
||||||
|
Test a complete set of input values for an external credential before
|
||||||
|
saving it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
view_name = _('External Credential Type Test')
|
||||||
|
|
||||||
|
model = models.CredentialType
|
||||||
|
serializer_class = serializers.EmptySerializer
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
test_inputs = request.data.get('inputs', {})
|
||||||
|
try:
|
||||||
|
obj.plugin.backend(None, **test_inputs)
|
||||||
|
return Response({}, status=status.HTTP_202_ACCEPTED)
|
||||||
|
except Exception as exc:
|
||||||
|
return Response({'inputs': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
class HostRelatedSearchMixin(object):
|
class HostRelatedSearchMixin(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -577,6 +577,16 @@ class CredentialType(CommonModelNameNotUnique):
|
|||||||
if field.get('ask_at_runtime', False) is True
|
if field.get('ask_at_runtime', False) is True
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def plugin(self):
|
||||||
|
if self.kind != 'external':
|
||||||
|
raise AttributeError('plugin')
|
||||||
|
[plugin] = [
|
||||||
|
plugin for ns, plugin in credential_plugins.items()
|
||||||
|
if ns == self.namespace
|
||||||
|
]
|
||||||
|
return plugin
|
||||||
|
|
||||||
def default_for_field(self, field_id):
|
def default_for_field(self, field_id):
|
||||||
for field in self.inputs.get('fields', []):
|
for field in self.inputs.get('fields', []):
|
||||||
if field['id'] == field_id:
|
if field['id'] == field_id:
|
||||||
@@ -1336,11 +1346,7 @@ class CredentialInputSource(PrimordialModel):
|
|||||||
super(CredentialInputSource, self).save(*args, **kwargs)
|
super(CredentialInputSource, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def get_input_value(self):
|
def get_input_value(self):
|
||||||
[backend] = [
|
backend = self.source_credential.credential_type.plugin.backend
|
||||||
plugin.backend for ns, plugin in credential_plugins.items()
|
|
||||||
if ns == self.source_credential.credential_type.namespace
|
|
||||||
]
|
|
||||||
|
|
||||||
backend_kwargs = {}
|
backend_kwargs = {}
|
||||||
for field_name, value in self.source_credential.inputs.items():
|
for field_name, value in self.source_credential.inputs.items():
|
||||||
if field_name in self.source_credential.credential_type.secret_fields:
|
if field_name in self.source_credential.credential_type.secret_fields:
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ function AddCredentialsController (
|
|||||||
$scope,
|
$scope,
|
||||||
strings,
|
strings,
|
||||||
componentsStrings,
|
componentsStrings,
|
||||||
ConfigService
|
ConfigService,
|
||||||
|
ngToast,
|
||||||
|
$filter
|
||||||
) {
|
) {
|
||||||
const vm = this || {};
|
const vm = this || {};
|
||||||
|
|
||||||
@@ -36,6 +38,7 @@ function AddCredentialsController (
|
|||||||
vm.form.credential_type._route = 'credentials.add.credentialType';
|
vm.form.credential_type._route = 'credentials.add.credentialType';
|
||||||
vm.form.credential_type._model = credentialType;
|
vm.form.credential_type._model = credentialType;
|
||||||
vm.form.credential_type._placeholder = strings.get('inputs.CREDENTIAL_TYPE_PLACEHOLDER');
|
vm.form.credential_type._placeholder = strings.get('inputs.CREDENTIAL_TYPE_PLACEHOLDER');
|
||||||
|
vm.isTestable = credentialType.get('kind') === 'external';
|
||||||
|
|
||||||
const gceFileInputSchema = {
|
const gceFileInputSchema = {
|
||||||
id: 'gce_service_account_key',
|
id: 'gce_service_account_key',
|
||||||
@@ -62,6 +65,8 @@ function AddCredentialsController (
|
|||||||
become._choices = Array.from(apiConfig.become_methods, method => method[0]);
|
become._choices = Array.from(apiConfig.become_methods, method => method[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm.isTestable = credentialType.get('kind') === 'external';
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
},
|
},
|
||||||
_source: vm.form.credential_type,
|
_source: vm.form.credential_type,
|
||||||
@@ -69,6 +74,45 @@ function AddCredentialsController (
|
|||||||
_key: 'inputs'
|
_key: 'inputs'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vm.form.secondary = ({ inputs }) => {
|
||||||
|
const name = $filter('sanitize')(credentialType.get('name'));
|
||||||
|
const endpoint = `${credentialType.get('id')}/test/`;
|
||||||
|
|
||||||
|
return credentialType.http.post({ url: endpoint, data: { inputs }, replace: false })
|
||||||
|
.then(() => {
|
||||||
|
ngToast.success({
|
||||||
|
content: `
|
||||||
|
<div class="Toast-wrapper">
|
||||||
|
<div class="Toast-icon">
|
||||||
|
<i class="fa fa-check-circle Toast-successIcon"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>${name}:</b> ${strings.get('edit.TEST_PASSED')}
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
dismissButton: false,
|
||||||
|
dismissOnTimeout: true
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(({ data }) => {
|
||||||
|
const msg = data.inputs ? `${$filter('sanitize')(data.inputs)}` : strings.get('edit.TEST_FAILED');
|
||||||
|
|
||||||
|
ngToast.danger({
|
||||||
|
content: `
|
||||||
|
<div class="Toast-wrapper">
|
||||||
|
<div class="Toast-icon">
|
||||||
|
<i class="fa fa-exclamation-triangle Toast-successIcon"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>${name}:</b> ${msg}
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
dismissButton: false,
|
||||||
|
dismissOnTimeout: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
vm.form.save = data => {
|
vm.form.save = data => {
|
||||||
data.user = me.get('id');
|
data.user = me.get('id');
|
||||||
|
|
||||||
@@ -149,7 +193,9 @@ AddCredentialsController.$inject = [
|
|||||||
'$scope',
|
'$scope',
|
||||||
'CredentialsStrings',
|
'CredentialsStrings',
|
||||||
'ComponentsStrings',
|
'ComponentsStrings',
|
||||||
'ConfigService'
|
'ConfigService',
|
||||||
|
'ngToast',
|
||||||
|
'$filter'
|
||||||
];
|
];
|
||||||
|
|
||||||
export default AddCredentialsController;
|
export default AddCredentialsController;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
</at-input-group>
|
</at-input-group>
|
||||||
|
|
||||||
<at-action-group col="12" pos="right">
|
<at-action-group col="12" pos="right">
|
||||||
|
<at-form-action type="secondary" ng-if="vm.isTestable"></at-form-action>
|
||||||
<at-form-action type="cancel" to="credentials"></at-form-action>
|
<at-form-action type="cancel" to="credentials"></at-form-action>
|
||||||
<at-form-action type="save"></at-form-action>
|
<at-form-action type="save"></at-form-action>
|
||||||
</at-action-group>
|
</at-action-group>
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ function CredentialsStrings (BaseString) {
|
|||||||
PANEL_TITLE: t.s('NEW CREDENTIAL')
|
PANEL_TITLE: t.s('NEW CREDENTIAL')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ns.edit = {
|
||||||
|
TEST_PASSED: t.s('Test passed.'),
|
||||||
|
TEST_FAILED: t.s('Test failed.')
|
||||||
|
};
|
||||||
|
|
||||||
ns.permissions = {
|
ns.permissions = {
|
||||||
TITLE: t.s('CREDENTIALS PERMISSIONS')
|
TITLE: t.s('CREDENTIALS PERMISSIONS')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ function EditCredentialsController (
|
|||||||
$scope,
|
$scope,
|
||||||
strings,
|
strings,
|
||||||
componentsStrings,
|
componentsStrings,
|
||||||
ConfigService
|
ConfigService,
|
||||||
|
ngToast,
|
||||||
|
Wait,
|
||||||
|
$filter,
|
||||||
) {
|
) {
|
||||||
const vm = this || {};
|
const vm = this || {};
|
||||||
|
|
||||||
@@ -83,6 +86,7 @@ function EditCredentialsController (
|
|||||||
vm.form.credential_type._value = credentialType.get('id');
|
vm.form.credential_type._value = credentialType.get('id');
|
||||||
vm.form.credential_type._displayValue = credentialType.get('name');
|
vm.form.credential_type._displayValue = credentialType.get('name');
|
||||||
vm.form.credential_type._placeholder = strings.get('inputs.CREDENTIAL_TYPE_PLACEHOLDER');
|
vm.form.credential_type._placeholder = strings.get('inputs.CREDENTIAL_TYPE_PLACEHOLDER');
|
||||||
|
vm.isTestable = (isEditable && credentialType.get('kind') === 'external');
|
||||||
|
|
||||||
const gceFileInputSchema = {
|
const gceFileInputSchema = {
|
||||||
id: 'gce_service_account_key',
|
id: 'gce_service_account_key',
|
||||||
@@ -124,6 +128,7 @@ function EditCredentialsController (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
vm.isTestable = (isEditable && credentialType.get('kind') === 'external');
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
},
|
},
|
||||||
@@ -132,6 +137,45 @@ function EditCredentialsController (
|
|||||||
_key: 'inputs'
|
_key: 'inputs'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vm.form.secondary = ({ inputs }) => {
|
||||||
|
const name = $filter('sanitize')(credentialType.get('name'));
|
||||||
|
const endpoint = `${credential.get('id')}/test/`;
|
||||||
|
|
||||||
|
return credential.http.post({ url: endpoint, data: { inputs }, replace: false })
|
||||||
|
.then(() => {
|
||||||
|
ngToast.success({
|
||||||
|
content: `
|
||||||
|
<div class="Toast-wrapper">
|
||||||
|
<div class="Toast-icon">
|
||||||
|
<i class="fa fa-check-circle Toast-successIcon"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>${name}:</b> ${strings.get('edit.TEST_PASSED')}
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
dismissButton: false,
|
||||||
|
dismissOnTimeout: true
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(({ data }) => {
|
||||||
|
const msg = data.inputs ? `${$filter('sanitize')(data.inputs)}` : strings.get('edit.TEST_FAILED');
|
||||||
|
|
||||||
|
ngToast.danger({
|
||||||
|
content: `
|
||||||
|
<div class="Toast-wrapper">
|
||||||
|
<div class="Toast-icon">
|
||||||
|
<i class="fa fa-exclamation-triangle Toast-successIcon"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>${name}:</b> ${msg}
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
dismissButton: false,
|
||||||
|
dismissOnTimeout: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a credential's `credential_type` is changed while editing, the inputs associated with
|
* If a credential's `credential_type` is changed while editing, the inputs associated with
|
||||||
* the old type need to be cleared before saving the inputs associated with the new type.
|
* the old type need to be cleared before saving the inputs associated with the new type.
|
||||||
@@ -210,7 +254,10 @@ EditCredentialsController.$inject = [
|
|||||||
'$scope',
|
'$scope',
|
||||||
'CredentialsStrings',
|
'CredentialsStrings',
|
||||||
'ComponentsStrings',
|
'ComponentsStrings',
|
||||||
'ConfigService'
|
'ConfigService',
|
||||||
|
'ngToast',
|
||||||
|
'Wait',
|
||||||
|
'$filter',
|
||||||
];
|
];
|
||||||
|
|
||||||
export default EditCredentialsController;
|
export default EditCredentialsController;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
.at-ActionGroup {
|
.at-ActionGroup {
|
||||||
margin-top: @at-margin-panel;
|
margin-top: @at-margin-panel;
|
||||||
|
|
||||||
button:last-child {
|
button {
|
||||||
margin-left: @at-margin-panel-inset;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ function atFormActionController ($state, strings) {
|
|||||||
case 'save':
|
case 'save':
|
||||||
vm.setSaveDefaults();
|
vm.setSaveDefaults();
|
||||||
break;
|
break;
|
||||||
|
case 'secondary':
|
||||||
|
vm.setSecondaryDefaults();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
vm.setCustomDefaults();
|
vm.setCustomDefaults();
|
||||||
}
|
}
|
||||||
@@ -43,6 +46,13 @@ function atFormActionController ($state, strings) {
|
|||||||
scope.color = 'success';
|
scope.color = 'success';
|
||||||
scope.action = () => { form.submit(); };
|
scope.action = () => { form.submit(); };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vm.setSecondaryDefaults = () => {
|
||||||
|
scope.text = strings.get('TEST');
|
||||||
|
scope.fill = '';
|
||||||
|
scope.color = 'info';
|
||||||
|
scope.action = () => { form.submitSecondary(); };
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
atFormActionController.$inject = ['$state', 'ComponentsStrings'];
|
atFormActionController.$inject = ['$state', 'ComponentsStrings'];
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<button class="btn at-Button{{ fill }}--{{ color }}"
|
<button class="btn at-Button{{ fill }}--{{ color }}"
|
||||||
ng-disabled="type !== 'cancel' && (form.disabled || (type === 'save' && !form.isValid))"
|
ng-disabled="type !== 'cancel' && (form.disabled
|
||||||
|
|| (type === 'save' && !form.isValid))
|
||||||
|
|| (type === 'secondary' && !form.isValid)"
|
||||||
ng-click="action()">
|
ng-click="action()">
|
||||||
{{::text}}
|
{{::text}}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -62,6 +62,40 @@ function AtFormController (eventService, strings) {
|
|||||||
scope.$apply(vm.submit);
|
scope.$apply(vm.submit);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vm.getSubmitData = () => vm.components
|
||||||
|
.filter(component => component.category === 'input')
|
||||||
|
.reduce((values, component) => {
|
||||||
|
if (component.state._value === undefined) {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.state._format === 'selectFromOptions') {
|
||||||
|
values[component.state.id] = component.state._value[0];
|
||||||
|
} else if (component.state._key && typeof component.state._value === 'object') {
|
||||||
|
values[component.state.id] = component.state._value[component.state._key];
|
||||||
|
} else if (component.state._group) {
|
||||||
|
values[component.state._key] = values[component.state._key] || {};
|
||||||
|
values[component.state._key][component.state.id] = component.state._value;
|
||||||
|
} else {
|
||||||
|
values[component.state.id] = component.state._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
vm.submitSecondary = () => {
|
||||||
|
if (!vm.state.isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.state.disabled = true;
|
||||||
|
|
||||||
|
const data = vm.getSubmitData();
|
||||||
|
|
||||||
|
scope.state.secondary(data)
|
||||||
|
.finally(() => { vm.state.disabled = false; });
|
||||||
|
};
|
||||||
|
|
||||||
vm.submit = () => {
|
vm.submit = () => {
|
||||||
if (!vm.state.isValid) {
|
if (!vm.state.isValid) {
|
||||||
return;
|
return;
|
||||||
@@ -69,26 +103,7 @@ function AtFormController (eventService, strings) {
|
|||||||
|
|
||||||
vm.state.disabled = true;
|
vm.state.disabled = true;
|
||||||
|
|
||||||
const data = vm.components
|
const data = vm.getSubmitData();
|
||||||
.filter(component => component.category === 'input')
|
|
||||||
.reduce((values, component) => {
|
|
||||||
if (component.state._value === undefined) {
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component.state._format === 'selectFromOptions') {
|
|
||||||
values[component.state.id] = component.state._value[0];
|
|
||||||
} else if (component.state._key && typeof component.state._value === 'object') {
|
|
||||||
values[component.state.id] = component.state._value[component.state._key];
|
|
||||||
} else if (component.state._group) {
|
|
||||||
values[component.state._key] = values[component.state._key] || {};
|
|
||||||
values[component.state._key][component.state.id] = component.state._value;
|
|
||||||
} else {
|
|
||||||
values[component.state.id] = component.state._value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
scope.state.save(data)
|
scope.state.save(data)
|
||||||
.then(scope.state.onSaveSuccess)
|
.then(scope.state.onSaveSuccess)
|
||||||
|
|||||||
@@ -153,17 +153,22 @@ function httpPost (config = {}) {
|
|||||||
const req = {
|
const req = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: this.path,
|
url: this.path,
|
||||||
data: config.data
|
data: config.data,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.url) {
|
if (config.url) {
|
||||||
req.url = `${this.path}${config.url}`;
|
req.url = `${this.path}${config.url}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!('replace' in config)) {
|
||||||
|
config.replace = true;
|
||||||
|
}
|
||||||
|
|
||||||
return $http(req)
|
return $http(req)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.model.GET = res.data;
|
if (config.replace) {
|
||||||
|
this.model.GET = res.data;
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ function BaseStringService (namespace) {
|
|||||||
this.COPY = t.s('COPY');
|
this.COPY = t.s('COPY');
|
||||||
this.YES = t.s('YES');
|
this.YES = t.s('YES');
|
||||||
this.CLOSE = t.s('CLOSE');
|
this.CLOSE = t.s('CLOSE');
|
||||||
|
this.TEST = t.s('TEST');
|
||||||
this.SUCCESSFUL_CREATION = resource => t.s('{{ resource }} successfully created', { resource: $filter('sanitize')(resource) });
|
this.SUCCESSFUL_CREATION = resource => t.s('{{ resource }} successfully created', { resource: $filter('sanitize')(resource) });
|
||||||
|
|
||||||
this.deleteResource = {
|
this.deleteResource = {
|
||||||
|
|||||||
Reference in New Issue
Block a user