def update_object(self, data: (dict, CmdbObject), user: UserModel = None, permission: AccessControlPermission = None) -> str: if isinstance(data, dict): update_object = CmdbObject(**data) elif isinstance(data, CmdbObject): update_object = data else: raise ObjectManagerUpdateError( 'Wrong CmdbObject init format - expecting CmdbObject or dict') update_object.last_edit_time = datetime.utcnow() if user: update_object.editor_id = user.public_id type_ = self._type_manager.get(update_object.type_id) verify_access(type_, user, permission) ack = self._update(collection=CmdbObject.COLLECTION, public_id=update_object.get_public_id(), data=update_object.__dict__) # create cmdb.core.object.updated event if self._event_queue and user: event = Event( "cmdb.core.object.updated", { "id": update_object.get_public_id(), "type_id": update_object.get_type_id(), "user_id": user.get_public_id() }) self._event_queue.put(event) return ack.acknowledged
def delete_job(public_id: int, request_user: UserModel): try: try: job_instance = exportd_manager.get_job(public_id) log_params = { 'job_id': job_instance.get_public_id(), 'state': True, 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'event': LogAction.DELETE.name, 'message': '', } log_manager.insert_log(action=LogAction.DELETE, log_type=ExportdJobLog.__name__, **log_params) except (ExportdJobManagerGetError, LogManagerInsertError) as err: LOGGER.error(err) return abort(404) ack = exportd_manager.delete_job(public_id=public_id, request_user=request_user) except ExportdJobManagerDeleteError: return abort(400) except CMDBError: return abort(500) resp = make_response(ack) return resp
def update_template(self, data: (dict, DocapiTemplate), request_user: UserModel) -> str: """ Update new DocapiTemplat Object Args: data: init data request_user: current user, to detect who triggered event Returns: Public ID of the DocapiTemplate in database """ if isinstance(data, dict): update_object = DocapiTemplate(**data) elif isinstance(data, DocapiTemplate): update_object = data else: raise DocapiTemplateManagerUpdateError( f'Could not update template with ID: {data.get_public_id()}') update_object.last_execute_date = datetime.utcnow() ack = self._update(collection=DocapiTemplate.COLLECTION, public_id=update_object.get_public_id(), data=update_object.to_database()) if self._event_queue: event = Event( "cmdb.docapi.updated", { "id": update_object.get_public_id(), "active": update_object.get_active(), "user_id": request_user.get_public_id() }) self._event_queue.put(event) return ack.acknowledged
def run_job_manual(self, public_id: int, request_user: UserModel) -> bool: if self._event_queue: event = Event("cmdb.exportd.run_manual", {"id": public_id, "user_id": request_user.get_public_id(), "event": 'manuel'}) self._event_queue.put(event) return True
def delete_object(self, public_id: int, user: UserModel, permission: AccessControlPermission = None): type_id = self.get_object(public_id=public_id).type_id type_ = self._type_manager.get(type_id) if not type_.active: raise AccessDeniedError( f'Objects cannot be removed because type `{type_.name}` is deactivated.' ) verify_access(type_, user, permission) try: if self._event_queue: event = Event( "cmdb.core.object.deleted", { "id": public_id, "type_id": self.get_object(public_id).get_type_id(), "user_id": user.get_public_id(), "event": 'delete' }) self._event_queue.put(event) ack = self._delete(CmdbObject.COLLECTION, public_id) return ack except (CMDBError, Exception): raise ObjectDeleteError(msg=public_id)
def update_file(request_user: UserModel): """ This method updates a file to the specified section in the document. Any existing value that matches the file name and metadata is taken into account. Furthermore, it is checked whether the current file name already exists in the directory. If this is the case, 'copy_(index)_' is appended as prefix. The method is executed recursively. Exception, if the parameter 'attachment' is passed with the value '{reference':true}', the name is not checked. Note: Create a unique media file element: - Folders in the same directory are unique. - The folder name can exist in different directories Create sub-folders: - Selected folder is considered as parent folder This also applies to files Changes: Is stored under 'request.json' Raises: MediaFileManagerUpdateError: If something went wrong during update. Args: Args: request_user (User): the instance of the started user (last modifier) Returns: MediaFile as JSON """ try: add_data_dump = json.dumps(request.json) new_file_data = json.loads(add_data_dump, object_hook=json_util.object_hook) reference_attachment = json.loads(request.args.get('attachment')) data = media_file_manager.get_file( metadata={'public_id': new_file_data['public_id']}) data['public_id'] = new_file_data['public_id'] data['filename'] = new_file_data['filename'] data['metadata'] = new_file_data['metadata'] data['metadata']['author_id'] = new_file_data['metadata'][ 'author_id'] = request_user.get_public_id() # Check if file / folder exist in folder if not reference_attachment['reference']: checker = { 'filename': new_file_data['filename'], 'metadata.parent': new_file_data['metadata']['parent'] } copied_name = create_attachment_name(new_file_data['filename'], 0, checker, media_file_manager) data['filename'] = copied_name media_file_manager.updata_file(data) except MediaFileManagerUpdateError: return abort(500) resp = make_response(data) return resp
def worker(job: ExportdJob, request_user: UserModel): from flask import make_response as make_res from cmdb.exportd.exporter_base import ExportdManagerBase from cmdb.event_management.event import Event try: event = Event( "cmdb.exportd.run_manual", { "id": job.get_public_id(), "user_id": request_user.get_public_id(), "event": 'manuel' }) content = ExportdManagerBase(job, object_manager, log_manager, event).execute( request_user.public_id, request_user.get_display_name(), False) response = make_res(content.data, content.status) response.headers['Content-Type'] = '%s; charset=%s' % ( content.mimetype, content.charset) return response except Exception as err: LOGGER.error(err) return abort(404)
def update_job(self, data: (dict, ExportdJob), request_user: UserModel, event_start=True) -> str: """ Update new ExportdJob Object Args: data: init data request_user: current user, to detect who triggered event event_start: Controls whether an event should be started Returns: Public ID of the ExportdJob in database """ if isinstance(data, dict): update_object = ExportdJob(**data) elif isinstance(data, ExportdJob): update_object = data else: raise ExportdJobManagerUpdateError(f'Could not update job with ID: {data.get_public_id()}') update_object.last_execute_date = datetime.utcnow() ack = self._update( collection=ExportdJob.COLLECTION, public_id=update_object.get_public_id(), data=update_object.to_database() ) if self._event_queue and event_start: event = Event("cmdb.exportd.updated", {"id": update_object.get_public_id(), "active": update_object.scheduling["event"]["active"] and update_object.get_active(), "user_id": request_user.get_public_id()}) self._event_queue.put(event) return ack.acknowledged
def delete_many_objects(self, filter_query: dict, public_ids, user: UserModel): ack = self._delete_many(CmdbObject.COLLECTION, filter_query) if self._event_queue: event = Event("cmdb.core.objects.deleted", {"ids": public_ids, "user_id": user.get_public_id(), "event": 'delete'}) self._event_queue.put(event) return ack
def delete_object(public_id: int, request_user: UserModel): try: current_object_instance = object_manager.get_object(public_id) current_type_instance = object_manager.get_type( current_object_instance.get_type_id()) current_object_render_result = CmdbRender( object_instance=current_object_instance, object_manager=object_manager, type_instance=current_type_instance, render_user=request_user).result() except ObjectManagerGetError as err: LOGGER.error(err) return abort(404) except RenderError as err: LOGGER.error(err) return abort(500) try: ack = object_manager.delete_object( public_id=public_id, user=request_user, permission=AccessControlPermission.DELETE) except ObjectManagerGetError as err: return abort(400, err.message) except AccessDeniedError as err: return abort(403, err.message) except ObjectDeleteError: return abort(400) except CMDBError: return abort(500) try: # generate log log_data = { 'object_id': public_id, 'version': current_object_render_result.object_information['version'], 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'comment': 'Object was deleted', 'render_state': json.dumps(current_object_render_result, default=default).encode('UTF-8') } log_manager.insert(action=LogAction.DELETE, log_type=CmdbObjectLog.__name__, **log_data) except (CMDBError, LogManagerInsertError) as err: LOGGER.error(err) resp = make_response(ack) return resp
def delete_template(self, public_id: int, request_user: UserModel) -> bool: try: ack = self._delete(collection=DocapiTemplate.COLLECTION, public_id=public_id) if self._event_queue: event = Event("cmdb.docapi.deleted", {"id": public_id, "active": False, "user_id": request_user.get_public_id()}) self._event_queue.put(event) return ack except Exception: raise DocapiTemplateManagerDeleteError(f'Could not delete template with ID: {public_id}')
def delete_job(self, public_id: int, request_user: UserModel) -> bool: try: ack = self._delete(collection=ExportdJob.COLLECTION, public_id=public_id) if self._event_queue: event = Event("cmdb.exportd.deleted", {"id": public_id, "active": False, "user_id": request_user.get_public_id()}) self._event_queue.put(event) return ack except Exception: raise ExportdJobManagerDeleteError(f'Could not delete job with ID: {public_id}')
def add_job(request_user: UserModel): from bson import json_util add_data_dump = json.dumps(request.json) try: new_job_data = json.loads(add_data_dump, object_hook=json_util.object_hook) new_job_data['public_id'] = exportd_manager.get_new_id( ExportdJob.COLLECTION) new_job_data['last_execute_date'] = datetime.utcnow() new_job_data['author_id'] = request_user.get_public_id() new_job_data['author_name'] = request_user.get_display_name() new_job_data['state'] = ExecuteState.SUCCESSFUL.name except TypeError as e: LOGGER.warning(e) abort(400) try: job_instance = ExportdJob(**new_job_data) except CMDBError as e: LOGGER.debug(e) return abort(400) try: ack = exportd_manager.insert_job(job_instance) except ExportdJobManagerInsertError: return abort(500) # Generate new insert log try: log_params = { 'job_id': job_instance.get_public_id(), 'state': True, 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'event': LogAction.CREATE.name, 'message': '', } log_manager.insert_log(action=LogAction.CREATE, log_type=ExportdJobLog.__name__, **log_params) except LogManagerInsertError as err: LOGGER.error(err) resp = make_response(ack) return resp
def delete_object(self, public_id: int, user: UserModel, permission: AccessControlPermission = None): type_id = self.get_object(public_id=public_id).type_id type_ = self._type_manager.get(type_id) verify_access(type_, user, permission) try: if self._event_queue: event = Event( "cmdb.core.object.deleted", { "id": public_id, "type_id": self.get_object(public_id).get_type_id(), "user_id": user.get_public_id() }) self._event_queue.put(event) ack = self._delete(CmdbObject.COLLECTION, public_id) return ack except (CMDBError, Exception): raise ObjectDeleteError(msg=public_id)
def update_job(request_user: UserModel): from bson import json_util add_data_dump = json.dumps(request.json) new_job_data = None try: new_job_data = json.loads(add_data_dump, object_hook=json_util.object_hook) except TypeError as e: LOGGER.warning(e) abort(400) try: state = new_job_data["state"] update_job_instance = ExportdJob(**new_job_data) except CMDBError: return abort(400) try: exportd_manager.update_job(update_job_instance, request_user, False) except ExportdJobManagerUpdateError: return abort(500) # Generate new insert log if state not in ExecuteState.RUNNING.name: try: log_params = { 'job_id': update_job_instance.get_public_id(), 'state': True, 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'event': LogAction.EDIT.name, 'message': '', } log_manager.insert_log(action=LogAction.EDIT, log_type=ExportdJobLog.__name__, **log_params) except LogManagerInsertError as err: LOGGER.error(err) resp = make_response(update_job_instance) return resp
def add_template(request_user: UserModel): from bson import json_util add_data_dump = json.dumps(request.json) try: new_tpl_data = json.loads(add_data_dump, object_hook=json_util.object_hook) new_tpl_data['public_id'] = docapi_tpl_manager.get_new_id() new_tpl_data['author_id'] = request_user.get_public_id() except TypeError as err: LOGGER.warning(err) abort(400) try: template_instance = DocapiTemplate(**new_tpl_data) except CMDBError as err: LOGGER.debug(err) return abort(400) try: ack = docapi_tpl_manager.insert_template(template_instance) except DocapiTemplateManagerInsertError: return abort(500) resp = make_response(ack) return resp
def update_object(self, data: (dict, CmdbObject), user: UserModel = None, permission: AccessControlPermission = None) -> str: if isinstance(data, dict): update_object = CmdbObject(**data) elif isinstance(data, CmdbObject): update_object = data else: raise ObjectManagerUpdateError( 'Wrong CmdbObject init format - expecting CmdbObject or dict') update_object.last_edit_time = datetime.now(timezone.utc) if user: update_object.editor_id = user.public_id type_ = self._type_manager.get(update_object.type_id) if not type_.active: raise AccessDeniedError( f'Objects cannot be updated because type `{type_.name}` is deactivated.' ) verify_access(type_, user, permission) ack = self._update(collection=CmdbObject.COLLECTION, public_id=update_object.get_public_id(), data=update_object.__dict__) if self._event_queue and user: event = Event( "cmdb.core.object.updated", { "id": update_object.get_public_id(), "type_id": update_object.get_type_id(), "user_id": user.get_public_id(), 'event': 'update' }) self._event_queue.put(event) return ack.acknowledged
def update_object_state(public_id: int, request_user: UserModel): if isinstance(request.json, bool): state = request.json else: return abort(400) try: founded_object = object_manager.get_object(public_id=public_id) except ObjectManagerGetError as err: LOGGER.error(err) return abort(404) if founded_object.active == state: return make_response(False, 204) try: founded_object.active = state update_ack = object_manager.update_object( founded_object, user=request_user, permission=AccessControlPermission.READ) except AccessDeniedError as err: return abort(403, err.message) except ObjectManagerUpdateError as err: LOGGER.error(err) return abort(500) # get current object state try: current_type_instance = object_manager.get_type( founded_object.get_type_id()) current_object_render_result = CmdbRender( object_instance=founded_object, object_manager=object_manager, type_instance=current_type_instance, render_user=request_user).result() except ObjectManagerGetError as err: LOGGER.error(err) return abort(404) except RenderError as err: LOGGER.error(err) return abort(500) try: # generate log change = {'old': not state, 'new': state} log_data = { 'object_id': public_id, 'version': founded_object.version, 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'render_state': json.dumps(current_object_render_result, default=default).encode('UTF-8'), 'comment': 'Active status has changed', 'changes': change, } log_manager.insert(action=LogAction.ACTIVE_CHANGE, log_type=CmdbObjectLog.__name__, **log_data) except (CMDBError, LogManagerInsertError) as err: LOGGER.error(err) return make_response(update_ack)
def delete_many_objects(public_ids, request_user: UserModel): try: ids = [] operator_in = {'$in': []} filter_public_ids = {'public_id': {}} for v in public_ids.split(","): try: ids.append(int(v)) except (ValueError, TypeError): return abort(400) operator_in.update({'$in': ids}) filter_public_ids.update({'public_id': operator_in}) ack = [] objects = object_manager.get_objects_by(**filter_public_ids) for current_object_instance in objects: try: current_type_instance = object_manager.get_type( current_object_instance.get_type_id()) current_object_render_result = CmdbRender( object_instance=current_object_instance, object_manager=object_manager, type_instance=current_type_instance, render_user=request_user).result() except ObjectManagerGetError as err: LOGGER.error(err) return abort(404) except RenderError as err: LOGGER.error(err) return abort(500) try: ack.append( object_manager.delete_object( public_id=current_object_instance.get_public_id(), user=request_user, permission=AccessControlPermission.DELETE)) except ObjectDeleteError: return abort(400) except AccessDeniedError as err: return abort(403, err.message) except CMDBError: return abort(500) try: # generate log log_data = { 'object_id': current_object_instance.get_public_id(), 'version': current_object_render_result.object_information['version'], 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'comment': 'Object was deleted', 'render_state': json.dumps(current_object_render_result, default=default).encode('UTF-8') } log_manager.insert(action=LogAction.DELETE, log_type=CmdbObjectLog.__name__, **log_data) except (CMDBError, LogManagerInsertError) as err: LOGGER.error(err) resp = make_response({'successfully': ack}) return resp except ObjectDeleteError as e: return jsonify(message='Delete Error', error=e.message) except CMDBError: return abort(500)
def update_object(public_id: int, request_user: UserModel): object_ids = request.args.getlist('objectIDs') if len(object_ids) > 0: object_ids = list(map(int, object_ids)) else: object_ids = [public_id] update_ack = None for obj_id in object_ids: # get current object state try: current_object_instance = object_manager.get_object(obj_id) current_type_instance = object_manager.get_type( current_object_instance.get_type_id()) current_object_render_result = CmdbRender( object_instance=current_object_instance, type_instance=current_type_instance, render_user=request_user, object_manager=object_manager, ref_render=True).result() except ObjectManagerGetError as err: LOGGER.error(err) return abort(404) except RenderError as err: LOGGER.error(err) return abort(500) update_comment = '' # load put data try: # get data as str add_data_dump = json.dumps(request.json) # convert into python dict put_data = json.loads(add_data_dump, object_hook=object_hook) # check for comment try: put_data['public_id'] = obj_id put_data[ 'creation_time'] = current_object_instance.creation_time put_data['author_id'] = current_object_instance.author_id old_fields = list( map( lambda x: {k: v for k, v in x.items() if k in ['name', 'value']}, current_type_instance.get_fields())) new_fields = put_data['fields'] for item in new_fields: for old in old_fields: if item['name'] == old['name']: old['value'] = item['value'] put_data['fields'] = old_fields if 'active' not in put_data: put_data['active'] = current_object_instance.active if 'version' not in put_data: put_data['version'] = current_object_instance.version update_comment = put_data['comment'] del put_data['comment'] except (KeyError, IndexError, ValueError): update_comment = '' except TypeError as e: LOGGER.warning(e) return abort(400) # update edit time put_data['last_edit_time'] = datetime.now(timezone.utc) try: update_object_instance = CmdbObject(**put_data) except ObjectManagerUpdateError as err: LOGGER.error(err) return abort(400) # calc version changes = current_object_instance / update_object_instance if len(changes['new']) == 1: update_object_instance.update_version( update_object_instance.VERSIONING_PATCH) elif len(changes['new']) == len(update_object_instance.fields): update_object_instance.update_version( update_object_instance.VERSIONING_MAJOR) elif len(changes['new']) > (len(update_object_instance.fields) / 2): update_object_instance.update_version( update_object_instance.VERSIONING_MINOR) else: update_object_instance.update_version( update_object_instance.VERSIONING_PATCH) # insert object try: update_ack = object_manager.update_object( update_object_instance, request_user, AccessControlPermission.UPDATE) except ManagerGetError as err: return abort(404, err.message) except AccessDeniedError as err: return abort(403, err.message) except CMDBError as e: LOGGER.warning(e) return abort(500) try: # generate log log_data = { 'object_id': obj_id, 'version': current_object_render_result.object_information['version'], 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'comment': update_comment, 'changes': changes, 'render_state': json.dumps(current_object_render_result, default=default).encode('UTF-8') } log_manager.insert(action=LogAction.EDIT, log_type=CmdbObjectLog.__name__, **log_data) except (CMDBError, LogManagerInsertError) as err: LOGGER.error(err) return make_response(update_ack)
def insert_object(request_user: UserModel): from bson import json_util add_data_dump = json.dumps(request.json) try: new_object_data = json.loads(add_data_dump, object_hook=json_util.object_hook) if not 'public_id' in new_object_data: new_object_data['public_id'] = object_manager.get_new_id( CmdbObject.COLLECTION) if not 'active' in new_object_data: new_object_data['active'] = True new_object_data['creation_time'] = datetime.now(timezone.utc) new_object_data['views'] = 0 new_object_data['version'] = '1.0.0' # default init version except TypeError as e: LOGGER.warning(e) abort(400) try: new_object_id = object_manager.insert_object( new_object_data, user=request_user, permission=AccessControlPermission.CREATE) except ManagerGetError as err: return abort(404, err.message) except AccessDeniedError as err: return abort(403, err.message) except ObjectInsertError as err: LOGGER.error(err) return abort(400, str(err)) # get current object state try: current_type_instance = object_manager.get_type( new_object_data['type_id']) current_object = object_manager.get_object(new_object_id) current_object_render_result = CmdbRender( object_instance=current_object, object_manager=object_manager, type_instance=current_type_instance, render_user=request_user).result() except ObjectManagerGetError as err: LOGGER.error(err) return abort(404) except RenderError as err: LOGGER.error(err) return abort(500) # Generate new insert log try: log_params = { 'object_id': new_object_id, 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'comment': 'Object was created', 'render_state': json.dumps(current_object_render_result, default=default).encode('UTF-8'), 'version': current_object.version } log_ack = log_manager.insert(action=LogAction.CREATE, log_type=CmdbObjectLog.__name__, **log_params) except LogManagerInsertError as err: LOGGER.error(err) resp = make_response(new_object_id) return resp
def import_objects(request_user: UserModel): # Check if file exists if not request.files: return abort(400, 'No import file was provided') request_file: FileStorage = get_file_in_request('file', request.files) filename = secure_filename(request_file.filename) working_file = f'/tmp/{filename}' request_file.save(working_file) # Load file format file_format = request.form.get('file_format', None) # Load parser config parser_config: dict = get_element_from_data_request('parser_config', request) or {} if parser_config == {}: LOGGER.info('No parser config was provided - using default parser config') # Check for importer config importer_config_request: dict = get_element_from_data_request('importer_config', request) or None if not importer_config_request: return abort(400, 'No import config was provided') # Check if type exists try: type_manager = TypeManager(database_manager=current_app.database_manager) type_ = type_manager.get(importer_config_request.get('type_id')) if not type_.active: raise AccessDeniedError(f'Objects cannot be created because type `{type_.name}` is deactivated.') verify_import_access(user=request_user, _type=type_, _manager=type_manager) except ObjectManagerGetError as err: return abort(404, err.message) except AccessDeniedError as err: return abort(403, err.message) # Load parser try: parser_class = load_parser_class('object', file_format) except ParserLoadError as ple: return abort(406, ple.message) parser = parser_class(parser_config) LOGGER.info(f'Parser {parser_class} was loaded') # Load importer config try: importer_config_class = load_importer_config_class('object', file_format) except ImporterLoadError as ile: return abort(406, ile.message) importer_config = importer_config_class(**importer_config_request) LOGGER.debug(importer_config_request) # Load importer try: importer_class = load_importer_class('object', file_format) except ImporterLoadError as ile: return abort(406, ile.message) importer = importer_class(working_file, importer_config, parser, object_manager, request_user) LOGGER.info(f'Importer {importer_class} was loaded') try: import_response: ImporterObjectResponse = importer.start_import() except ImportRuntimeError as ire: LOGGER.error(f'Error while importing objects: {ire.message}') return abort(500, ire.message) except AccessDeniedError as err: return abort(403, err.message) # close request file request_file.close() # log all successful imports for message in import_response.success_imports: try: # get object state of every imported object current_type_instance = object_manager.get_type(importer_config_request.get('type_id')) current_object = object_manager.get_object(message.public_id) current_object_render_result = CmdbRender(object_instance=current_object, type_instance=current_type_instance, render_user=request_user, object_manager=object_manager).result() # insert object create log log_params = { 'object_id': message.public_id, 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'comment': 'Object was imported', 'render_state': json.dumps(current_object_render_result, default=default).encode('UTF-8'), 'version': current_object.version } log_manager.insert(action=LogAction.CREATE, log_type=CmdbObjectLog.__name__, **log_params) except ObjectManagerGetError as err: LOGGER.error(err) return abort(404) except RenderError as err: LOGGER.error(err) return abort(500) except LogManagerInsertError as err: LOGGER.error(err) return make_response(import_response)
def update_object(public_id: int, data: dict, request_user: UserModel): object_ids = request.args.getlist('objectIDs') if len(object_ids) > 0: object_ids = list(map(int, object_ids)) else: object_ids = [public_id] manager = ObjectManager(database_manager=current_app.database_manager, event_queue=current_app.event_queue) results: [dict] = [] failed = [] for obj_id in object_ids: # deep copy active_state = request.get_json().get('active', None) new_data = copy.deepcopy(data) try: current_object_instance = manager.get( obj_id, user=request_user, permission=AccessControlPermission.READ) current_type_instance = type_manager.get( current_object_instance.get_type_id()) current_object_render_result = CmdbRender( object_instance=current_object_instance, object_manager=object_manager, type_instance=current_type_instance, render_user=request_user).result() update_comment = '' try: # check for comment new_data['public_id'] = obj_id new_data[ 'creation_time'] = current_object_instance.creation_time new_data['author_id'] = current_object_instance.author_id new_data[ 'active'] = active_state if active_state else current_object_instance.active if 'version' not in data: new_data['version'] = current_object_instance.version old_fields = list( map( lambda x: {k: v for k, v in x.items() if k in ['name', 'value']}, current_object_render_result.fields)) new_fields = data['fields'] for item in new_fields: for old in old_fields: if item['name'] == old['name']: old['value'] = item['value'] new_data['fields'] = old_fields update_comment = data['comment'] del new_data['comment'] except (KeyError, IndexError, ValueError): update_comment = '' except TypeError as err: LOGGER.error( f'Error: {str(err.args)} Object: {json.dumps(new_data, default=default)}' ) failed.append( ResponseFailedMessage(error_message=str(err.args), status=400, public_id=obj_id, obj=new_data).to_dict()) continue # update edit time new_data['last_edit_time'] = datetime.now(timezone.utc) new_data['editor_id'] = request_user.public_id update_object_instance = CmdbObject( **json.loads(json.dumps(new_data, default=json_util.default), object_hook=object_hook)) # calc version changes = current_object_instance / update_object_instance if len(changes['new']) == 1: new_data['version'] = update_object_instance.update_version( update_object_instance.VERSIONING_PATCH) elif len(changes['new']) == len(update_object_instance.fields): new_data['version'] = update_object_instance.update_version( update_object_instance.VERSIONING_MAJOR) elif len( changes['new']) > (len(update_object_instance.fields) / 2): new_data['version'] = update_object_instance.update_version( update_object_instance.VERSIONING_MINOR) else: new_data['version'] = update_object_instance.update_version( update_object_instance.VERSIONING_PATCH) manager.update(obj_id, new_data, request_user, AccessControlPermission.UPDATE) results.append(new_data) # Generate log entry try: log_data = { 'object_id': obj_id, 'version': update_object_instance.get_version(), 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'comment': update_comment, 'changes': changes, 'render_state': json.dumps(update_object_instance, default=default).encode('UTF-8') } log_manager.insert(action=LogAction.EDIT, log_type=CmdbObjectLog.__name__, **log_data) except (CMDBError, LogManagerInsertError) as err: LOGGER.error(err) except AccessDeniedError as err: LOGGER.error(err) return abort(403) except ObjectManagerGetError as err: LOGGER.error(err) failed.append( ResponseFailedMessage(error_message=err.message, status=400, public_id=obj_id, obj=new_data).to_dict()) continue except (ManagerGetError, ObjectManagerUpdateError) as err: LOGGER.error(err) failed.append( ResponseFailedMessage(error_message=err.message, status=404, public_id=obj_id, obj=new_data).to_dict()) continue except (CMDBError, RenderError) as e: LOGGER.warning(e) failed.append( ResponseFailedMessage(error_message=str(e.__repr__), status=500, public_id=obj_id, obj=new_data).to_dict()) continue api_response = UpdateMultiResponse(results=results, failed=failed, url=request.url, model=CmdbObject.MODEL) return api_response.make_response()