def dataset_commit(request, app, data): if not isinstance(data, dict): raise SuspiciousOperation('Invalid payload') # For backwards compatibility if 'changes' in data: data['changed'] = list(data['changes'].values()) # Convert keys back to integers (json doesn't handle integer keys) for object_id, change in data['changes'].items(): change['object_id'] = int(object_id) kwargs = {} for key, value in data.items(): validate_func = globals().get('_validate_commit_' + key) if validate_func: if not isinstance(value, list): raise SuspiciousOperation('Invalid commit {}'.format(key)) for item in value: validate_func(item) kwargs[key] = value try: commit_query(app=app, **kwargs) except ValidationError as error: return { 'status': 'error', 'type': error.__class__.__name__, 'message': str(error), } return { 'status': 'success', }
def commit(request): try: commit_obj = json.loads(request.POST['commit']) except (KeyError, ValueError) as error: result = { 'status': 'error', 'message': str(error), } else: changed = [] if 'changes' in commit_obj: for key, value in commit_obj['changes'].items(): value['object_id'] = int(key) changed.append(value) deleted = commit_obj.get('deleted', []) user = request.user try: commit_query(changed=changed, deleted=deleted, user=user) except (PermissionDenied, ValidationError) as error: result = { 'status': 'error', 'message': str(error), } else: result = {'status': 'success'} return HttpResponse(json.dumps(result), content_type='application/x-json')
def restore_deleted(request, change_commit_id): object_id = request.POST.get('object_id') deleted = get_object_or_404( ChangeDelete, server_id=object_id, commit__pk=change_commit_id, ) server_obj = deleted.attributes # Remove consistent_via_attribute values they are implicit consistent_attribute_ids = ServertypeAttribute.objects.filter( servertype_id=server_obj['servertype']).exclude( consistent_via_attribute_id=None) for attribute in consistent_attribute_ids: server_obj.pop(attribute.attribute_id) try: commit = commit_query([server_obj], user=request.user) object_id = str(commit.created[0]['object_id']) except CommitError as error: messages.error(request, str(error)) else: messages.success(request, 'Restored object with new id ' + object_id) return redirect(reverse('serverdb_history') + '?object_id=' + object_id)
def restore_deleted(request, change_commit): deleted = get_object_or_404( ChangeDelete, server_id=request.POST.get('server_id'), commit__pk=change_commit, ) server_obj = deleted.attributes try: commit_query([server_obj], user=request.user) except CommitError as error: messages.error(request, str(error)) else: messages.success(request, 'Server restored.') return redirect( reverse('serverdb_history') + '?server_id=' + str(server_obj['object_id']))
def dataset_create(request, app, data): required = [ 'attributes', ] if not all(key in data for key in required): raise SuspiciousOperation('Invalid create request') if not isinstance(data['attributes'], dict): raise SuspiciousOperation('Attributes must be a dictionary') try: commit_obj = commit_query([data['attributes']], app=app) except ValidationError as error: return { 'status': 'error', 'type': error.__class__.__name__, 'message': str(error), } return { 'status': 'success', 'result': commit_obj.created, }
def _edit(request, server, edit_mode=False, template='edit'): # NOQA: C901 invalid_attrs = set() if edit_mode and request.POST: attribute_lookup = { a.pk: a for a in Attribute.objects.filter( attribute_id__in=(k[len('attr_'):] for k in request.POST.keys())) } attribute_lookup.update(Attribute.specials) for key, value in request.POST.items(): if not key.startswith('attr_'): continue attribute_id = key[len('attr_'):] attribute = attribute_lookup[attribute_id] value = value.strip() if attribute.multi: values = [v.strip() for v in value.splitlines()] try: value = attribute.from_str(values) except ValidationError: invalid_attrs.add(attribute_id) value = set(values) elif value == '': value = None else: try: value = attribute.from_str(value) except ValidationError: invalid_attrs.add(attribute_id) server[attribute_id] = value if not invalid_attrs: if server.object_id: action = 'edited' created = [] changed = [server._serialize_changes()] else: action = 'created' created = [server] changed = [] try: commit_obj = commit_query(created, changed, user=request.user) except (PermissionDenied, ValidationError) as err: messages.error(request, str(err)) else: messages.success(request, 'Server successfully ' + action) if action == 'created': server = commit_obj.created[0] url = '{0}?object_id={1}'.format( reverse('servershell_inspect'), server.object_id, ) return HttpResponseRedirect(url) if invalid_attrs: messages.error(request, 'Attributes contain invalid values') servertype = Servertype.objects.get(pk=server['servertype']) attribute_lookup = { a.pk: a for a in Attribute.objects.filter(attribute_id__in=(server.keys())) } attribute_lookup.update(Attribute.specials) servertype_attributes = { sa.attribute_id: sa for sa in (ServertypeAttribute.objects.filter( servertype_id=server['servertype'])) } fields = [] fields_set = set() for key, value in server.items(): if (key == 'object_id' or key == 'intern_ip' and servertype.ip_addr_type == 'null'): continue attribute = attribute_lookup[key] servertype_attribute = servertype_attributes.get(key) if servertype_attribute and servertype_attribute.related_via_attribute: continue fields_set.add(key) fields.append({ 'key': key, 'value': value, 'type': attribute.type, 'multi': attribute.multi, 'required': (servertype_attribute and servertype_attribute.required or key in Attribute.specials.keys()), 'regexp_display': _prepare_regexp_html(attribute.regexp), 'regexp': ( # XXX: HTML5 input patterns do not support these None if not attribute.regexp else attribute.regexp.replace( '\\A', '^').replace('\\Z', '$')), 'default': (servertype_attribute and servertype_attribute.default_value), 'readonly': attribute.readonly, 'error': key in invalid_attrs, }) fields.sort(key=lambda k: (not k['required'], k['key'])) return TemplateResponse( request, 'servershell/{}.html'.format(template), { 'object_id': server.object_id, 'fields': fields, 'is_ajax': request.is_ajax(), 'base_template': 'empty.html' if request.is_ajax() else 'base.html', 'link': request.get_full_path(), })
def commit(self, app=None, user=None): commit_obj = self._build_commit_object() commit_query(app=app, user=user, **commit_obj) self._confirm_changes()
def _edit(request, server, edit_mode=False, template='edit'): # NOQA: C901 # @TODO work with ServerAttribute models here and use Django forms invalid_attrs = set() if edit_mode and request.POST: attribute_lookup = { a.pk: a for a in Attribute.objects.filter( attribute_id__in=(k[len('attr_'):] for k in request.POST.keys())) } attribute_lookup.update(Attribute.specials) # Get current values to be able to submit only changes current = None if server['object_id']: current = Query({ 'object_id': server['object_id'] }, list(attribute_lookup.keys())).get() for key, value in request.POST.items(): if not key.startswith('attr_'): continue attribute_id = key[len('attr_'):] attribute = attribute_lookup[attribute_id] value = value.strip() if attribute.multi: values = [v.strip() for v in value.splitlines()] try: value = attribute.from_str(values) except ValidationError: invalid_attrs.add(attribute_id) value = set(values) elif value == '': value = None else: try: value = attribute.from_str(value) except ValidationError: invalid_attrs.add(attribute_id) if attribute_id not in server.keys(): messages.error(request, 'Unknown attribute {}'.format(attribute_id)) continue if current: # TODO: Remove when PR153 is merged if type(current[attribute_id]) in (IPv4Address, IPv6Address): current[attribute_id] = ip_interface(current[attribute_id]) # Submit only changes if current[attribute_id] != value: server[attribute_id] = value else: server[attribute_id] = value if not invalid_attrs: if server.object_id: action = 'edited' created = [] changes = server._serialize_changes() if len(changes.keys()) > 1: changed = [changes] else: # Only object_id has been passed and we do not support # changing it (yet). changed = [] else: action = 'created' created = [server] changed = [] if not created and not changed: messages.info(request, str('Nothing has changed.')) else: try: commit_obj = commit_query(created, changed, user=request.user) except (PermissionDenied, ValidationError) as err: messages.error(request, str(err)) else: messages.success(request, 'Server successfully ' + action) if action == 'created': server = commit_obj.created[0] url = '{0}?object_id={1}'.format( reverse('servershell_inspect'), server.object_id, ) return HttpResponseRedirect(url) if invalid_attrs: messages.error(request, 'Attributes contains invalid values') servertype = Servertype.objects.get(pk=server['servertype']) attribute_lookup = { a.pk: a for a in Attribute.objects.filter(attribute_id__in=(server.keys())) } attribute_lookup.update(Attribute.specials) servertype_attributes = { sa.attribute_id: sa for sa in (ServertypeAttribute.objects.filter( servertype_id=server['servertype'])) } fields = [] fields_set = set() for key, value in server.items(): if (key == 'object_id' or key == 'intern_ip' and servertype.ip_addr_type == 'null'): continue attribute = attribute_lookup[key] servertype_attribute = servertype_attributes.get(key) if servertype_attribute and servertype_attribute.related_via_attribute: continue fields_set.add(key) fields.append({ 'key': key, 'value': value, 'type': attribute.type, 'multi': attribute.multi, 'required': (servertype_attribute and servertype_attribute.required or key in Attribute.specials.keys()), 'regexp_display': _prepare_regexp_html(attribute.regexp), 'regexp': ( # XXX: HTML5 input patterns do not support these None if not attribute.regexp else attribute.regexp.replace( '\\A', '^').replace('\\Z', '$')), 'default': (servertype_attribute and servertype_attribute.default_value), 'readonly': attribute.readonly, 'error': key in invalid_attrs, 'hovertext': attribute.hovertext, }) fields.sort(key=lambda k: (not k['required'], k['key'])) return TemplateResponse( request, 'servershell/{}.html'.format(template), { 'object_id': server.object_id, 'hostname': server['hostname'], 'fields': fields, 'is_ajax': request.is_ajax(), 'base_template': 'empty.html' if request.is_ajax() else 'base.html', 'link': request.get_full_path(), })