def capture_rollback(db_id, db_name, coll_name, change, coll_id = None): """"Capture diff which will allow roll-back of edits db_id -- ID of DB change applies to db_name -- Name of DB change applies to coll_name -- Name of collection change applies to change -- The change to be made, as a diff item ( entry in diff['diffs']) coll_id -- Supply if this is a field edit and so coll_id is known Roll-backs can be applied using apply_rollback. Their format is a diff, with extra 'post' field storing the state after change, and the live field which should be unset if they are applied """ return {} is_record = False #Fetch the current state if coll_id is None and coll_name is not None: current_record = idc.get_coll(db_id, coll_name) elif coll_id is None: current_record = idc.get_db(db_name) else: try: current_record = idc.get_field(coll_id, change['item'], type = 'human') #Try as a field first assert current_record is not None and current_record['err'] is False except: #Now try as a record current_record = idc.get_record(coll_id, change['item']) is_record = True if current_record is None: #Should not happen really, but if it does we can't do anything return None #Create a roll-back document field = change["field"] prior = change.copy() if coll_id is None and coll_name is not None: if ih.is_special_field(change["item"]): prior['content'] = current_record['data'][change["item"][2:-2]][field] elif ih.is_toplevel_field(change['item']): prior['content'] = current_record['data'][field] else: prior['content'] = current_record['data'][change["item"]][field] elif coll_id is None: prior['content'] = current_record['data'][field] elif is_record: prior['content'] = current_record['data'][field] else: prior['content'] = current_record['data']['data'][field] #This can be applied like the diffs from the web-frontend, but has an extra field rollback_diff = {"db":db_name, "collection":coll_name, "diffs":[prior], "post":change, "live":True} return rollback_diff
def capture_rollback(inv_db, db_id, db_name, coll_name, change, coll_id = None): """"Capture diff which will allow roll-back of edits inv_db -- connection to inventory_db db_id -- ID of DB change applies to db_name -- Name of DB change applies to coll_name -- Name of collection change applies to change -- The change to be made, as a diff item ( entry in diff['diffs']) coll_id -- Supply if this is a field edit and so coll_id is known Roll-backs can be applied using apply_rollback. Their format is a diff, with extra 'post' field storing the state after change, and the live field which should be unset if they are applied """ is_record = False #Fetch the current state if coll_id is None and coll_name is not None: current_record = idc.get_coll(inv_db, db_id, coll_name) elif coll_id is None: current_record = idc.get_db(inv_db, db_name) else: try: current_record = idc.get_field(inv_db, coll_id, change['item'], type = 'human') #Try as a field first assert current_record is not None and current_record['err'] is False except: #Now try as a record current_record = idc.get_record(inv_db, coll_id, change['item']) is_record = True if current_record is None: #Should not happen really, but if it does we can't do anything return None #Create a roll-back document field = change["field"] prior = change.copy() if coll_id is None and coll_name is not None: if ih.is_special_field(change["item"]): prior['content'] = current_record['data'][change["item"][2:-2]][field] elif ih.is_toplevel_field(change['item']): prior['content'] = current_record['data'][field] else: prior['content'] = current_record['data'][change["item"]][field] elif coll_id is None: prior['content'] = current_record['data'][field] elif is_record: prior['content'] = current_record['data'][field] else: prior['content'] = current_record['data']['data'][field] #This can be applied like the diffs from the web-frontend, but has an extra field rollback_diff = {"db":db_name, "collection":coll_name, "diffs":[prior], "post":change, "live":True} return rollback_diff
def capture_rollback(db_id, db_name, table_name, change, table_id = None): """"Capture diff which will allow roll-back of edits db_id -- ID of DB change applies to db_name -- Name of DB change applies to table_name -- Name of table change applies to change -- The change to be made, as a diff item ( entry in diff['diffs']) table_id -- Supply if this is a field edit and so table_id is known Roll-backs can be applied using apply_rollback. Their format is a diff, with extra 'post' field storing the state after change, and the live field which should be unset if they are applied """ #Fetch the current state if table_id is None and table_name is not None: current_record = idc.get_table(table_name) elif table_id is None: current_record = idc.get_db(db_name) else: current_record = idc.get_field(table_id, change['item'], type = 'human') if current_record is None: #Should not happen really, but if it does we can't do anything return None #Create a roll-back document field = change["field"] prior = change.copy() if table_id is None and table_name is not None: if ih.is_special_field(change["item"]): prior['content'] = current_record['data'][change["item"][2:-2]][field] elif ih.is_toplevel_field(change['item']): prior['content'] = current_record['data'][field] else: prior['content'] = current_record['data'][change["item"]][field] elif table_id is None: prior['content'] = current_record['data'][field] else: prior['content'] = current_record['data']['data'][field] #This can be applied like the diffs from the web-frontend, but has an extra field rollback_diff = {"db":db_name, "table":table_name, "diffs":[prior], "post":change, "live":True} return rollback_diff
def process_edits(diff): #This has to reverse anything we did to display info #We also edit the diff if there's anything to be done diffs = diff["diffs"] for index, diff_item in enumerate(diffs): if diff_item['field'] == "example": str = diff_item['content'] str = ih.transform_examples(str, True) diffs[index]['content'] = str #We allow editing of nice_names in two ways, so we patch the diff accordingly here #If current state is {"item":"__INFO__","field":"nice_name"... we want to change __INFO__ to 'top_level' for index, diff_item in enumerate(diffs): if diff_item['item'] == '__INFO__' and diff_item['field'] == 'nice_name': diff_item['item'] = 'top_level' if not ih.is_toplevel_field(diff_item['item']): raise DiffKeyError("Cannot identify top-level state") return diff
def process_edits(diff): #This has to reverse anything we did to display info #We also edit the diff if there's anything to be done diffs = diff["diffs"] for index, diff_item in enumerate(diffs): if diff_item['field'] == "example": str = diff_item['content'] str = ih.transform_examples(str, True) inv.log_dest.info(str) diffs[index]['content'] = str #We allow editing of nice_names in two ways, so we patch the diff accordingly here #If current state is {"item":"__INFO__","field":"nice_name"... we want to change __INFO__ to 'top_level' for index, diff_item in enumerate(diffs): if diff_item['item'] == '__INFO__' and diff_item['field'] == 'nice_name': diff_item['item'] = 'top_level' if not ih.is_toplevel_field(diff_item['item']): raise DiffKeyError("Cannot identify top-level state") return diff
def update_fields(diff, storeRollback=True): """Update a record from a diff object. diff -- should be a fully qualified difference, containing db, table names and then a list of changes, each being a dict containing the item, the field and the new content. Item corresponds to an entry in an object, field to the piece of information this specifies (for example, type, description, example) e.g. {"db":"hgcwa","table":"hgcwa_passports","diffs":[{"item":"total_label","field":"type","content":"string"}]} If this is a record entry, then the 'item' field will be a record hash. storeRollback -- determine whether to store the undiff and diff to allow rollback of the change """ try: if diff['table'] is not None: inv.log_dest.info("Updating descriptions for " + diff["table"]) else: inv.log_dest.info("Updating descriptions for " + diff["db"]) db_id = idc.get_db_id(diff["db"]) rollback = None try: for change in diff["diffs"]: if ih.is_special_field(change["item"]): if storeRollback: rollback = capture_rollback(db_id, diff["db"], diff["table"], change) change["item"] = change["item"][2:-2] #Trim special fields. TODO this should be done better somehow updated = idc.update_table_data(db_id, diff["table"], change["item"], change["field"], change["content"]) elif ih.is_toplevel_field(change["item"]): #Here we have item == "toplevel", field the relevant field, and change the new value if storeRollback: rollback = capture_rollback(db_id, diff["db"], diff["table"], change) #Only nice_name is currently an option if(change["field"] not in ['nice_name', 'status']): updated = {'err':True} else: if(diff["table"]): if(change['field']) == 'nice_name': new_nice = change['content'] new_stat = None else: new_nice = None new_stat = ih.status_to_code(change['content']) table_id = idc.get_table_id(diff['table']) updated = idc.update_table(table_id, nice_name=new_nice, status=new_stat) else: #Is database nice_name updated = idc.update_db(db_id, nice_name=change["content"]) else: table_id = idc.get_table_id(diff["table"]) if storeRollback: rollback = capture_rollback(db_id, diff["db"], diff["table"], change, table_id = table_id) updated = idc.update_field(table_id, change["item"], change["field"], change["content"], type="human") if updated['err']: raise KeyError("Cannot update, item not present") else: if storeRollback: store_rollback(rollback) except Exception as e: inv.log_dest.error("Error applying diff "+ str(change)+' '+str(e)) raise UpdateFailed(str(e)) except Exception as e: inv.log_dest.error("Error updating fields "+ str(e))
def update_fields(diff, storeRollback=True): """Update a record from a diff object. diff -- should be a fully qualified difference, containing db, table names and then a list of changes, each being a dict containing the item, the field and the new content. Item corresponds to an entry in an object, field to the piece of information this specifies (for example, type, description, example) e.g. {"db":"hgcwa","table":"hgcwa_passports","diffs":[{"item":"total_label","field":"type","content":"string"}]} If this is a record entry, then the 'item' field will be a record hash. storeRollback -- determine whether to store the undiff and diff to allow rollback of the change """ try: if diff['table'] is not None: inv.log_dest.info("Updating descriptions for " + diff["table"]) else: inv.log_dest.info("Updating descriptions for " + diff["db"]) db_id = idc.get_db_id(diff["db"]) rollback = None try: for change in diff["diffs"]: if ih.is_special_field(change["item"]): if storeRollback: rollback = capture_rollback(db_id, diff["db"], diff["table"], change) change["item"] = change["item"][ 2: -2] #Trim special fields. TODO this should be done better somehow updated = idc.update_table_data(db_id, diff["table"], change["item"], change["field"], change["content"]) elif ih.is_toplevel_field(change["item"]): #Here we have item == "toplevel", field the relevant field, and change the new value if storeRollback: rollback = capture_rollback(db_id, diff["db"], diff["table"], change) #Only nice_name is currently an option if (change["field"] not in ['nice_name', 'status']): updated = {'err': True} else: if (diff["table"]): if (change['field']) == 'nice_name': new_nice = change['content'] new_stat = None else: new_nice = None new_stat = ih.status_to_code(change['content']) table_id = idc.get_table_id(diff['table']) updated = idc.update_table(table_id, nice_name=new_nice, status=new_stat) else: #Is database nice_name updated = idc.update_db( db_id, nice_name=change["content"]) else: table_id = idc.get_table_id(diff["table"]) if storeRollback: rollback = capture_rollback(db_id, diff["db"], diff["table"], change, table_id=table_id) updated = idc.update_field(table_id, change["item"], change["field"], change["content"], type="human") if updated['err']: raise KeyError("Cannot update, item not present") else: if storeRollback: store_rollback(rollback) except Exception as e: inv.log_dest.error("Error applying diff " + str(change) + ' ' + str(e)) raise UpdateFailed(str(e)) except Exception as e: inv.log_dest.error("Error updating fields " + str(e))
def update_fields(diff, storeRollback=True): """Update a record from a diff object. diff -- should be a fully qualified difference, containing db, collection names and then a list of changes, each being a dict containing the item, the field and the new content. Item corresponds to an entry in an object, field to the piece of information this specifies (for example, type, description, example) e.g. {"db":"curve_automorphisms","collection":"passports","diffs":[{"item":"total_label","field":"type","content":"string"}]} If this is a record entry, then the 'item' field will be a record hash. storeRollback -- determine whether to store the undiff and diff to allow rollback of the change """ try: _id = idc.get_db_id(diff["db"]) rollback = None storeRollback = False try: for change in diff["diffs"]: if ih.is_special_field(change["item"]): if storeRollback: rollback = capture_rollback(_id['id'], diff["db"], diff["collection"], change) change["item"] = change["item"][2:-2] #Trim special fields. TODO this should be done better somehow updated = idc.update_coll_data(_id['id'], diff["collection"], change["item"], change["field"], change["content"]) elif ih.is_toplevel_field(change["item"]): #Here we have item == "toplevel", field the relevant field, and change the new value if storeRollback: rollback = capture_rollback(_id['id'], diff["db"], diff["collection"], change) #Only nice_name is currently an option print(change['field']) if(change["field"] not in ['nice_name', 'status']): updated = {'err':True} else: if(diff["collection"]): if(change['field']) == 'nice_name': new_nice = change['content'] new_stat = None else: new_nice = None new_stat = ih.status_to_code(change['content']) c_id = idc.get_coll_id(_id['id'], diff['collection']) updated = idc.update_coll(c_id['id'], nice_name=new_nice, status=new_stat) else: #Is database nice_name print(_id) updated = idc.update_db(_id['id'], nice_name=change["content"]) else: _c_id = idc.get_coll_id(_id['id'], diff["collection"]) if storeRollback: rollback = capture_rollback(_id['id'], diff["db"], diff["collection"], change, coll_id = _c_id['id']) succeeded = False #if it looks like a record, try treating as one #If this fails try it as a field if ih.is_probable_record_hash(change['item']): updated = idc.update_record_description(_c_id['id'], {'hash':change["item"], change["field"]:change["content"]}) if updated['err'] == False: succeeded = True; if not succeeded: updated = idc.update_field(_c_id['id'], change["item"], change["field"], change["content"], type="human") if updated['err']: raise KeyError("Cannot update, item not present") else: if storeRollback: store_rollback(rollback) except Exception as e: raise UpdateFailed(str(e)) except Exception as e: #inv.log_dest.error("Error updating fields "+ str(e)) pass
def update_fields(diff, storeRollback=True): """Update a record from a diff object. diff -- should be a fully qualified difference, containing db, collection names and then a list of changes, each being a dict containing the item, the field and the new content. Item corresponds to an entry in an object, field to the piece of information this specifies (for example, type, description, example) e.g. {"db":"curve_automorphisms","collection":"passports","diffs":[{"item":"total_label","field":"type","content":"string"}]} If this is a record entry, then the 'item' field will be a record hash. storeRollback -- determine whether to store the undiff and diff to allow rollback of the change """ try: got_client = inv.setup_internal_client(editor=True) assert(got_client == True) db = inv.int_client[inv.get_inv_db_name()] except Exception as e: inv.log_dest.error("Error getting Db connection "+ str(e)) return try: if diff['collection'] is not None: inv.log_dest.info("Updating descriptions for " + diff["db"]+'.'+diff["collection"]) else: inv.log_dest.info("Updating descriptions for " + diff["db"]) _id = idc.get_db_id(db, diff["db"]) rollback = None try: for change in diff["diffs"]: if ih.is_special_field(change["item"]): if storeRollback: rollback = capture_rollback(db, _id['id'], diff["db"], diff["collection"], change) change["item"] = change["item"][2:-2] #Trim special fields. TODO this should be done better somehow updated = idc.update_coll_data(db, _id['id'], diff["collection"], change["item"], change["field"], change["content"]) elif ih.is_toplevel_field(change["item"]): #Here we have item == "toplevel", field the relevant field, and change the new value if storeRollback: rollback = capture_rollback(db, _id['id'], diff["db"], diff["collection"], change) #Only nice_name is currently an option if(change["field"] not in ['nice_name', 'status']): updated = {'err':True} else: if(diff["collection"]): if(change['field']) == 'nice_name': new_nice = change['content'] new_stat = None else: new_nice = None new_stat = ih.status_to_code(change['content']) c_id = idc.get_coll_id(db, _id['id'], diff['collection']) updated = idc.update_coll(db, c_id['id'], nice_name=new_nice, status=new_stat) else: #Is database nice_name updated = idc.update_db(db, _id['id'], nice_name=change["content"]) else: _c_id = idc.get_coll_id(db, _id['id'], diff["collection"]) if storeRollback: rollback = capture_rollback(db, _id['id'], diff["db"], diff["collection"], change, coll_id = _c_id['id']) succeeded = False #if it looks like a record, try treating as one #If this fails try it as a field if ih.is_probable_record_hash(change['item']): updated = idc.update_record_description(db, _c_id['id'], {'hash':change["item"], change["field"]:change["content"]}) if updated['err'] == False: succeeded = True; if not succeeded: updated = idc.update_field(db, _c_id['id'], change["item"], change["field"], change["content"], type="human") if updated['err']: raise KeyError("Cannot update, item not present") else: if storeRollback: store_rollback(db, rollback) except Exception as e: inv.log_dest.error("Error applying diff "+ str(change)+' '+str(e)) raise UpdateFailed(str(e)) except Exception as e: inv.log_dest.error("Error updating fields "+ str(e))