def deleteListItem(repo_id, code, item_id): try: repo_id = int(repo_id) except TypeError: raise DbError(message="Invalid repo_id provided", context="List.deleteListItem", dberror="") try: result = db.run( "MATCH (r:Repository)--(l:List {code: {code}})-[x]-(i:ListItem) WHERE ID(r) = {repo_id} AND ID(i) = {item_id} DELETE i,x", { "repo_id": int(repo_id), "item_id": int(item_id), "code": code }) if result is not None: return True else: raise FindError(message="Could not find list item", context="List.deleteListItem", dberror="") except Exception as e: raise DbError(message="Could not delete list item", context="List.deleteListItem", dberror=e.message)
def getRecordCountForDataType(repo_id, type): repo_id = int(repo_id) try: type_id = int(type) except Exception: type_id = str(type) # TODO: check that repository is owned by current user try: if isinstance(type_id, int): count_obj = db.run( "MATCH (r:Repository)--(t:SchemaType)--(d:Data) WHERE ID(t) = {type_id} AND ID(r) = {repo_id} RETURN COUNT(d) as data_count", { "type_id": type_id, "repo_id": repo_id }).peek() else: count_obj = db.run( "MATCH (r:Repository)--(t:SchemaType)--(d:Data) WHERE t.code = {type_id} AND ID(r) = {repo_id} RETURN COUNT(d) as data_count", { "type_id": type_id, "repo_id": repo_id }).peek() return count_obj['data_count'] except Exception as e: raise DbError(message="Could not get data count for Data Type", context="Schema.getRecordCountForDataType", dberror=e.message)
def deleteType(repo_id, type_id): # TODO validate params # TODO: check that repository is owned by current user try: result = db.run( "MATCH (t:SchemaType)-[x]-(r:Repository) WHERE ID(r) = {repo_id} AND ID(t) = {type_id} OPTIONAL MATCH (f:SchemaField)-[y]-(t) OPTIONAL MATCH (d:Data)-[z]-(t) DELETE x,y,t,f,z,d", { "type_id": int(type_id), "repo_id": int(repo_id) }) print "type=" + type_id print "repo=" + repo_id if result is not None: SchemaManager.resetTypeInfoCache() return {"type_id": type_id} else: raise FindError(message="Could not find type", context="Schema.deleteType", dberror="") except Exception as e: raise DbError(message="Could not delete type", context="Schema.deleteType", dberror=e.message)
def getTypes(repo_id): # TODO validate params # TODO: check that repository is owned by current user try: result = db.run( "MATCH (t:SchemaType)--(r:Repository) WHERE ID(r) = {repo_id} RETURN ID(t) as id, t.name as name, t.code as code, t.description as description", {"repo_id": int(repo_id)}) if result: typelist = [] for r in result: t = { 'id': str(r['id']), 'name': r['name'], 'code': r['code'], 'description': r['description'] } # get fields i = SchemaManager.getInfoForType(repo_id, r['id']) t["fields"] = i["fields"] t["data_count"] = i["data_count"] typelist.append(t) return typelist except Exception as e: raise DbError(message="Could not get types", context="Schema.getTypes", dberror=e.message)
def checkFieldForData(repo_id, type_id, field_code): try: type_id = int(type) except Exception: type_id = str(type) try: if isinstance(type_id, int): result = db.run( "MATCH (r:Repository)--(s:SchemaType)--(d:Data) WHERE ID(r) = {repo_id} AND ID(s) = {type_id} AND d." + field_code + " <> '' return count(d) as data_count", { "repo_id": repo_id, "type_id": type_id }).peek() else: result = db.run( "MATCH (r:Repository)--(s:SchemaType)--(d:Data) WHERE ID(r) = {repo_id} AND s.code = {type_id} AND d." + field_code + " <> '' return count(d) as data_count", { "repo_id": repo_id, "type_id": type_id }).peek() if result is not None: data_count = result['data_count'] ret = {"data": False, "total": data_count} if data_count > 0: ret['data'] = True return ret except Exception as e: raise DbError(message="Could not get data count: " + e.message, context="Schema.checkFieldForData", dberror=e.message)
def add(repo_id, type_code, data, import_uuid=None, fields_created=None): # TODO: does user have access to this repo? data_proc, type_info = DataManager._validateData( repo_id, type_code, data, fields_created) try: q = "MATCH (t:SchemaType) WHERE ID(t) = {type_id} CREATE (n:Data " + makeDataMapForCypher( data_proc) + ")-[:IS]->(t) RETURN ID(n) AS id" data_proc["type_id"] = type_info[ "type_id"] # add type_id to data before insert res = db.run(q, data_proc).peek() data_id = res["id"] if import_uuid is not None: db.run( "MATCH (e:ImportEvent { uuid: {import_uuid}}), (n:Data) WHERE ID(n) = {data_id} CREATE (e)<-[x:IMPORTED_IN]-(n) RETURN ID(x) AS id", { "import_uuid": import_uuid, "data_id": data_id }) #DataManager.logChange("I", data_proc) return data_id except Exception as e: raise DbError(message="Could not create data (" + e.__class__.__name__ + ") " + e.message, context="DataManager.add", dberror=e.message)
def deleteField(repo_id, typecode, field_id): # TODO validate params # TODO: check that repository is owned by current user SchemaManager.resetTypeInfoCache() try: result = db.run( "MATCH (r:Repository)--(t:SchemaType {code: {typecode}})-[x]-(f:SchemaField) WHERE ID(r) = {repo_id} AND ID(f) = {field_id} DELETE f,x", { "repo_id": int(repo_id), "field_id": int(field_id), "typecode": typecode }) if result is not None: return True else: raise FindError(message="Could not find field", context="Schema.deleteField", dberror="") except Exception as e: raise DbError(message="Could not delete field", context="Schema.deleteField", dberror=e.message)
def deletePerson(person_id): try: result = db.run( "MATCH (n:Person) WHERE ID(n)={person_id} OPTIONAL MATCH (n)-[r]-() DELETE r,n", {"person_id": person_id}) except Exception as e: raise DbError(message="Could not delete person", context="People.deletePerson", dberror=e.message) # Check that we deleted something summary = result.consume() if summary.counters.nodes_deleted >= 1: return True raise FindError(message="Could not find person", context="People.deletePerson")
def addRelationship(start_node, end_node, type_id="RELATED", data=None): # TODO: does user have access to these nodes? try: type_id = re.sub(r'[^A-Za-z0-9_]+', '_', type_id) # NOTE: type_id is substituted directly into the string as the Bolt Neo4j driver doesn't allow placeholders for relationship types (yet) res = db.run( "MATCH (d1:Data), (d2:Data) WHERE ID(d1) = {start_node} AND ID(d2) = {end_node} CREATE(d1)-[r:" + type_id + "]->(d2) RETURN ID(r) AS id", { "start_node": start_node, "end_node": end_node, "type_id": type_id }).peek() return res["id"] except Exception as e: raise DbError(message="Could not create relationship", context="DataManager.addRelationship", dberror=e.message)
def update(node_id, data, import_uuid=None): # TODO: does user have access to this repo? try: id = int(node_id) except: id = node_id try: if isinstance(id, (int)): res = db.run( "MATCH (r:Repository)--(t:SchemaType)--(d:Data) WHERE ID(d) = {node_id} RETURN ID(r) as repo_id, ID(t) as type_id", { "node_id": id }).peek() else: res = db.run( "MATCH (r:Repository)--(t:SchemaType)--(d:Data) WHERE d.uuid = {uuid} RETURN ID(r) as repo_id, ID(t) as type_id", { "uuid": id }).peek() if res is None: return None data_proc, type_info = DataManager._validateData( int(res['repo_id']), int(res['type_id']), data) if isinstance(id, (int)): data_proc["node_id"] = id db.run( "MATCH (d:Data) WHERE ID(d) = {node_id} SET " + makeDataMapForCypher(data=data_proc, mode="U", prefix="d."), data_proc) else: data_proc["uuid"] = id db.run( "MATCH (d:Data) WHERE d.uuid = {uuid} SET " + makeDataMapForCypher(data=data_proc, mode="U", prefix="d."), data_proc) #DataManager.logChange("U", data_proc) return True except Exception as e: raise DbError(message="Could not update data", context="DataManager.update", dberror=e.message)
def deleteList(repo_id, list_id): try: result = db.run( "MATCH (l:List)-[x]-(r:Repository) WHERE ID(r) = {repo_id} AND ID(l) = {list_id} OPTIONAL MATCH (i:ListItem)-[y]-(l) DELETE x,y,l,i", { "list_id": int(list_id), "repo_id": int(repo_id) }) if result is not None: return {"list_id": list_id} else: raise FindError(message="Could not find list", context="Schema.deleteList", dberror="") except Exception as e: raise DbError(message="Could not delete list", context="Schema.deleteList", dberror=e.message)
def deleteRelationship(start_node=None, end_node=None, type_id=None, rel_id=None): # TODO: does user have access to relationship? try: if type_id is not None: type_str = "r:" + re.sub(r'[^A-Za-z0-9_]+', '_', type_id) else: type_str = "r" # NOTE: type_id is substituted directly into the string as the Bolt Neo4j driver doesn't allow placeholders for relationship types (yet) if end_node is None: if rel_id is None: rel_id = start_node # if rel_id is not set assume first positional parameter (start_node) is the rel_id if rel_id is None: return None # delete by rel_id db.run( "MATCH (d1:Data)-[" + type_str + "]-(d2:Data) WHERE ID(r) = {rel_id} DELETE r", {"rel_id": rel_id}) elif start_node is not None and end_node is not None: # delete by endpoints db.run( "MATCH (d1:Data)-[" + type_str + "]-(d2:Data) WHERE ID(d1) = {start_node} AND ID(d2) = {end_node} DELETE r", { "start_node": start_node, "end_node": end_node }) else: raise ParameterError( message="No relationship id or node id pair is set", context="DataManager.deleteRelationship") return True except Exception as e: raise DbError(message="Could not delete relationship", context="DataManager.deleteRelationship", dberror=e.message)
def getCountForType(repo_id, type_id): repo_id = int(repo_id) type_id = int(type_id) try: q_count = db.run( "MATCH (r:Repository)--(t:SchemaType)--(d:Data) WHERE ID(r)={repo_id} AND ID(t)={type_id} RETURN count(d) as data_count", { "repo_id": repo_id, "type_id": type_id }).peek() return { "repo_id": repo_id, "type_id": type_id, "data_count": q_count['data_count'] } except exception as e: raise DbError(message="Could get type Count", context="DataManager.getCountForType", dberror=e.message)
def delete(node_id, import_uuid=None): # TODO: does user have access to this repo? try: id = int(node_id) except: id = node_id try: if isinstance(id, (int)): db.run("MATCH (d:Data) WHERE ID(d) = {node_id} DELETE d", {"node_id": id}) else: db.run("MATCH (d:Data) WHERE d.uuid = {uuid} DELETE d", {"uuid": id}) # TODO: return false is no node is deleted? return True except Exception as e: raise DbError(message="Could not delete data", context="DataManager.delete", dberror=e.message)
def deleteDataFromRepo(repo_id, type_codes=None): # TODO: does user have access to this repo? type_str = "" if type_codes is not None: if all(isinstance(c, (int)) for c in type_codes): type_str = " AND ID(t) IN [" + ",".join(type_codes) + "] " else: type_codes = map( lambda x: '"' + re.sub(r'[^A-Za-z0-9_]+', '_', x) + '"', type_codes) type_str = " AND t.code IN [" + ",".join(type_codes) + "] " try: db.run( "MATCH (r:Repository)--(t:SchemaType)--(d:Data) WHERE ID(r) = {repo_id} " + type_str + " DETACH DELETE d", {"repo_id": repo_id}) return True except Exception as e: raise DbError(message="Could not delete data from repository", context="DataManager.deleteDataFromRepo", dberror=e.message)
def getType(repo_id, schema_id): # TODO validate params # TODO: check that repository is owned by current user try: res = db.run( "MATCH (r:Repository)--(t:SchemaType) WHERE ID(r) = {repo_id} AND ID(t) = {schema_id} RETURN ID(t) as id, t.name as name, t.code as code, t.description as description", { "repo_id": int(repo_id), "schema_id": int(schema_id) }).peek() if res: t = { 'id': str(res['id']), 'name': res['name'], 'code': res['code'], 'description': res['description'] } count_res = db.run( "MATCH (t:SchemaType)--(d:Data) WHERE ID(t) = {schema_id} RETURN count(d) as data_count", { "schema_id": int(schema_id) }).peek() if count_res: t['data_count'] = count_res['data_count'] else: t['data_count'] = 0 # get fields i = SchemaManager.getInfoForType(repo_id, res['id']) t["fields"] = i["fields"] return t except Exception as e: raise DbError(message="Could not get types", context="Schema.getType", dberror=e.message)
def getListsForRepo(repo_id): repo_id = int(repo_id) ret = {'lists': []} try: lists_res = db.run( "MATCH (r:Repository)--(l:List) WHERE ID(r) = {repo_id} RETURN ID(l) as id, l.name as name, l.code as code, l.description as description, l.merge_allowed as merge_allowed", {"repo_id": repo_id}) if lists_res: for i_list in lists_res: list_ret = { 'id': i_list['id'], 'name': i_list['name'], 'code': i_list['code'], 'description': i_list['description'], 'merge_allowed': i_list['merge_allowed'] } ret['lists'].append(list_ret) return ret else: return None except Exception as e: raise DbError(message="Could not get lists for repo", context="List.getListsForRepo", dberror=e.message)
def addField(repo_id, typecode, name, code, fieldtype, description, settings): # TODO validate params if typecode is None or len(typecode) == 0: raise ValidationError(message="Type code is required", context="Schema.addField") type_info = SchemaManager.getInfoForType(repo_id, typecode) SchemaManager.resetTypeInfoCache() if type_info is None: raise ValidationError(message="Type code is invalid", context="Schema.addField") typecode = type_info["code"] # always use code if code is None or len(code) == 0: raise ValidationError(message="Field code is required", context="Schema.addField") if name is None or len(name) == 0: raise ValidationError(message="Field name is required", context="Schema.addField") # Check field type if fieldtype not in SchemaManager.getDataTypes(): raise ValidationError(message="Invalid field type", context="Schema.addField") ret = {} ft = SchemaManager.getDataTypeInstance(fieldtype) if ft is None: raise ValidationError(message="Invalid field type", context="Schema.addField") sv = ft.validateSettings(settings) if sv is not True: raise SettingsValidationError(message="Invalid field type", errors={code: sv}, context="Schema.addField") # TODO: check that repository is owned by current user result = db.run( "MATCH (f:SchemaField {code: {code}})--(t:SchemaType {code: {typecode}})--(r:Repository) WHERE ID(r) = {repo_id} RETURN f.name as name, ID(f) as id", { "typecode": typecode, "code": code, "repo_id": int(repo_id) }).peek() if result is not None: ret['exists'] = True ret['field_id'] = result['id'] ret['name'] = result['name'] return ret else: flds = [ "name: {name}", "code: {code}", "description: {description}", "type: {fieldtype}" ] params = { "repo_id": int(repo_id), "name": name, "code": code, "description": description, "typecode": typecode, "fieldtype": fieldtype } for s in settings: flds.append("settings_" + s + ": {settings_" + s + "}") params["settings_" + s] = settings[s] result = db.run( "MATCH (r:Repository)--(t:SchemaType {code: {typecode}}) WHERE ID(r) = {repo_id} CREATE (f:SchemaField { " + ", ".join(flds) + " })-[:PART_OF]->(t) RETURN ID(f) as id, f.name as name, f.code as code", params) r = result.peek() # TODO: check query result if r: ret['exists'] = False ret['field_id'] = r['id'] ret['name'] = r['name'] ret['code'] = r['code'] return ret else: raise DbError(message="Could not add field", context="Schema.addField", dberror="")
def editListItem(repo_id, code, item_id, display, item_code, description=None): try: repo_id = int(repo_id) except TypeError: raise DbError(message="Invalid repo_id provided", context="List.editListItem", dberror="") if code is None or len(code) == 0: raise ValidationError(message="List code is required", context="List.editListItem") if item_code is None or len(item_code) == 0: raise ValidationError(message="List item code is required", context="List.editListItem") if display is None or len(display) == 0: raise ValidationError(message="List Item display is required", context="List.editListItem") ret = {} result = db.run( "MATCH (i:ListItem {code: {item_code}})--(l:List {code: {code}})--(r:Repository) WHERE ID(r) = {repo_id} AND ID(i) <> {item_id} RETURN ID(i) as id, i.display as display", { "item_code": item_code, "code": code, "repo_id": int(repo_id), "item_id": int(item_id) }).peek() if result is not None: ret['msg'] = "List Item already exists" ret['item_id'] = result['id'] ret['display'] = result['display'] return ret else: flds = [ "i.display = {display}", "i.code = {item_code}", "i.description = {description}" ] params = { "code": code, "repo_id": int(repo_id), "display": display, "item_code": item_code, "description": description, "item_id": int(item_id) } result = db.run( "MATCH (r:Repository)--(l:List {code: {code}})--(i:ListItem) WHERE ID(r) = {repo_id} AND ID(i) = {item_id} SET " + ", ".join(flds) + " RETURN ID(i) as id, i.display as display", params) r = result.peek() # TODO: check query result if r: ret['item_id'] = r['id'] ret['display'] = r['display'] return ret else: raise DbError(message="Could not edit list item", context="List.editListItem", dberror="")
def getInfoForType(repo_id, type): repo_id = int(repo_id) # TODO validate params try: type_id = int(type) except Exception: type_id = str(type) # TODO: check that repository is owned by current user try: if isinstance(type_id, int): tres = db.run( "MATCH (r:Repository)--(t:SchemaType) WHERE ID(t) = {type_id} AND ID(r) = {repo_id} RETURN ID(t) as id, t.name as name, t.code as code, t.description as description", { "type_id": type_id, "repo_id": repo_id }).peek() if tres is None: return None result = db.run( "MATCH (f:SchemaField)--(t:SchemaType)--(r:Repository) WHERE ID(t) = {type_id} AND ID(r) = {repo_id} RETURN ID(f) as id, f.name as name, f.code as code, f.type as type, f.description as description, properties(f) as props", { "type_id": int(type_id), "repo_id": repo_id }) else: tres = db.run( "MATCH (r:Repository)--(t:SchemaType) WHERE t.code = {code} AND ID(r) = {repo_id} RETURN ID(t) as id, t.name as name, t.code as code, t.description as description", { "code": type_id, "repo_id": repo_id }).peek() if tres is None: return None result = db.run( "MATCH (f:SchemaField)--(t:SchemaType)--(r:Repository) WHERE t.code = {code} AND ID(r) = {repo_id} RETURN ID(f) as id, f.name as name, f.code as code, f.type as type, f.description as description, properties(f) as props", { "code": type_id, "repo_id": repo_id }) info = { "type_id": tres['id'], "name": tres['name'], "code": tres['code'], "description": tres['description'] } fieldlist = [] if result: for r in result: ft = SchemaManager.getDataTypeInstance(r['type']) if ft is None: #raise ValidationError(message="Invalid field type", context="Schema.getFieldsForType") continue t = { 'id': str(r['id']), 'name': r['name'], 'code': r['code'], 'description': r['description'], 'type': r['type'], 'settings': {} } dc = SchemaManager.checkFieldForData( repo_id, type_id, r['code']) t['has_data'] = dc['data'] for s in ft.getSettingsList(): if "settings_" + s in r['props']: t["settings_" + s] = r['props']["settings_" + s] t["settings"][s] = r["props"]["settings_" + s] fieldlist.append(t) info["fields"] = fieldlist data_count = SchemaManager.getRecordCountForDataType( repo_id, type_id) info["data_count"] = data_count return info except Exception as e: raise DbError(message="Could not get fields for types", context="Schema.getFieldsForType", dberror=e.message)
def addType(repo_id, name, code, description, fields): # TODO validate params # TODO: check that repository is owned by current user ret = {"exists": False} try: result = db.run( "MATCH (t:SchemaType{code: {code}})--(r:Repository) WHERE ID(r) = {repo_id} RETURN ID(t) as id, t.name as name, t.code as code, t.description as description", { "code": code, "repo_id": int(repo_id) }) if result is not None and len(list(result)): ret = {"exists": True} for r in result: ret['type'] = { "id": r['id'], "name": r['name'], "code": r['code'], "description": r['description'] } return ret else: result = db.run( "MATCH (r:Repository) WHERE ID(r) = {repo_id} CREATE (t:SchemaType { name: {name}, code: {code}, description: {description}, storage: 'Graph'})-[:PART_OF]->(r) RETURN ID(t) as id", { "repo_id": int(repo_id), "name": name, "code": code, "description": description }) SchemaManager.resetTypeInfoCache() except Exception as e: raise DbError(message="Could not add type: " + e.message, context="Schema.addType", dberror=e.message) # add/edit fields field_status = {} settings = { f.replace("settings_", ""): v for f, v in fields.iteritems() if 'settings_' in f } for k in fields: # add field fret = SchemaManager.addField(repo_id, code, k['name'], k['code'], k['type'], k['description'], settings) if 'field_id' in fret: field_status[k['code']] = { 'status_code': 200, 'field_id': fret['field_id'], 'msg': 'Created new field' } else: field_status[k['code']] = { 'status_code': 200, 'field_id': None, 'msg': 'Could not create new field' } if result: for r in result: ret['type'] = { "id": r['id'], "name": name, "code": code, "description": description, "field_status": field_status } break else: raise DbError(message="Could not add type", context="Schema.addType", dberror="") return ret
def addListItem(repo_id, code, display, item_code, description=None): try: repo_id = int(repo_id) except TypeError: raise DbError(message="Invalid repo_id provided", context="List.addListItem", dberror="") ret = {} try: if code is None or len(code) == 0: raise ValidationError(message="List code is required", context="List.addListItem") list_info = ListManager.getInfoForList(repo_id, code) if list_info is None: raise ValidationError(message="List code is invalid", context="List.addListItem") if display is None: raise ValidationError(message="Display value is required", context="List.addListItem") if item_code is None: raise ValidationError(message="List Item Code is required", context="List.addListItem") if isinstance(code, int): item_result = db.run( "MATCH (i:ListItem {display: {display}})--(l:List {code: {code}})--(r:Repository) WHERE ID(r) = {repo_id} RETURN ID(i) as id, i.display as display", { "display": display, "code": code, "repo_id": repo_id }).peek() else: item_result = db.run( "MATCH (i:ListItem {display: {display}})--(l:List {code: {code}})--(r:Repository) WHERE ID(r) = {repo_id} RETURN ID(i) as id, i.display as display", { "display": display, "code": code, "repo_id": repo_id }).peek() if item_result is not None: ret['exists'] = True ret['item_id'] = item_result['id'] ret['display'] = item_result['display'] return ret else: item_flds = [ "display: {display}", "code: {item_code}", "description: {description}" ] item_params = { "list_code": code, "repo_id": repo_id, "display": display, "item_code": item_code, "description": description } add_result = db.run( "MATCH (r:Repository)--(l:List {code: {list_code}}) WHERE ID(r) = {repo_id} CREATE (i:ListItem {" + ", ".join(item_flds) + "})-[:PART_OF]->(l) RETURN ID(i) as id, i.display as display, i.code as code", item_params) r = add_result.peek() if r: ret['exists'] = False ret['item_id'] = r['id'] ret['display'] = r['display'] ret['code'] = r['code'] return ret else: raise DbError(message="Could not add List Item", context="List.addListItem", dberror="") except Exception as e: raise DbError(message="Could not add List Item", context="List.addListItem", dberror=e.message)
def addList(repo_id, name, code, merge_setting, description='', items={}): try: repo_id = int(repo_id) except TypeError: raise DbError(message="Invalid repo_id provided", context="List.addList", dberror="") ret = {"exists": False} try: result = db.run( "MATCH (l:List{code: {code}})--(r:Repository) WHERE ID(r) = {repo_id} RETURN ID(l) as id, l.name as name, l.code as code, l.description as description", { "code": code, "repo_id": int(repo_id) }).peek() if result: print result ret = { "exists": True, "id": result['id'], "code": result['code'], "name": result['name'], 'description': result['description'] } return ret else: result = db.run( "MATCH (r:Repository) WHERE ID(r) = {repo_id} CREATE (l:List {name: {name}, code: {code}, description: {description}, merge_allowed: {merge}, storage: 'Graph'})-[:PART_OF]->(r) return ID(l) as id", { "repo_id": repo_id, "name": name, "code": code, "description": description, "merge": merge_setting }).peek() except Exception as e: raise DbError(message="Could not add list: " + e.message, context="List.addList", dberror=e.message) #add/edit List Items item_status = {} for item in items: item_res = ListManager.addListItem(repo_id, code, item['display'], item['code'], item['description']) if 'item_id' in item_res: item_status[item['code']] = { 'status_code': 200, 'item_id': item_res['item_id'], 'msg': 'Created new list item' } else: item_status[item['code']] = { 'status_code': 200, 'item_id': None, 'msg': 'Could not create list item' } if result: ret = { 'id': result['id'], 'name': name, 'code': code, 'description': description, 'list_status': item_status } else: raise DbError(message="Could not add list", context="List.addList", dberror="") return ret
def editType(repo_id, type_id, name, code, description, fields, fieldsToDelete): # TODO validate params # TODO: check that repository is owned by current user result = db.run( "MATCH (r:Repository)--(t:SchemaType) WHERE ID(r) = {repo_id} AND ID(t) = {type_id} SET t.name = {name}, t.code = {code}, t.description = {description} RETURN ID(t) AS id", { "repo_id": int(repo_id), "type_id": int(type_id), "name": name, "code": code, "description": description }) # add/edit fields field_status = {} for k in fields: settings = { f.replace("settings_", ""): v for f, v in fields[k].iteritems() if 'settings_' in f } if 'id' in fields[k]: # edit existing field fret = SchemaManager.editField(repo_id, code, fields[k].get( 'id', ''), fields[k].get('name', ''), fields[k].get('code', ''), fields[k].get('type', ''), fields[k]['description'], settings) if 'field_id' in fret: field_status[fields[k]['code']] = { 'status_code': 200, 'field_id': fret['field_id'], 'msg': 'Edited field' } else: field_status[fields[k]['code']] = { 'status_code': 200, 'field_id': None, 'msg': 'Could not edit field' } else: # add field fret = SchemaManager.addField(repo_id, code, fields[k].get('name', ''), fields[k].get('code', ''), fields[k].get('type', ''), fields[k].get('description', ''), settings) if 'field_id' in fret: field_status[fields[k]['code']] = { 'status_code': 200, 'field_id': fret['field_id'], 'msg': 'Created new field' } else: field_status[fields[k]['code']] = { 'status_code': 200, 'field_id': None, 'msg': 'Could not create new field' } # delete fields if fieldsToDelete: for field_id in fieldsToDelete: SchemaManager.deleteField(repo_id, code, field_id) SchemaManager.resetTypeInfoCache() if result: ret = {} for r in result: ret['type'] = { "id": r['id'], "name": name, "code": code, "description": description, "field_status": field_status } return ret else: raise DbError(message="Could not edit type", context="Schema.editType", dberror="")
def editPerson(identity, forename, surname, location, email, url, tagline, is_disabled, nyunetid): if is_number(identity): ident_str = "ID(p)={identity}" identity = int(identity) else: ident_str = "p.email={identity}" update = [] if forename is not None: update.append("p.forename = {forename}") if surname is not None: update.append("p.surname = {surname}") if location is not None: update.append("p.location = {location}") if email is not None: update.append("p.email = {email}") if url is not None: update.append("p.url = {url}") if tagline is not None: update.append("p.tagline = {tagline}") if nyunetid is not None: update.append("p.nyunetid = {nyunetid}") if is_disabled is not None: print is_disabled try: is_disabled = int(is_disabled) if is_disabled <> 0: is_disabled = 1 update.append("p.is_disabled = {is_disabled}") except: pass update_str = "%s" % ", ".join(map(str, update)) if update_str != '' and update_str is not None: result = db.run( "MATCH (p:Person) WHERE " + ident_str + " SET " + update_str + " RETURN p.forename AS forename, p.surname AS surname, p.location AS location, p.email AS email, p.url AS url, p.tagline AS tagline, p.is_disabled AS is_disabled, p.nyunetid AS nyunetid", { "identity": identity, "forename": forename, "surname": surname, "location": location, "email": email, "url": url, "tagline": tagline, "is_disabled": is_disabled, "nyunetid": nyunetid }) if result: updated_person = {} for p in result: updated_person['forename'] = p['forename'] updated_person['surname'] = p['surname'] updated_person['name'] = str(p['forename']) + " " + str( p['surname']) updated_person['location'] = p['location'] updated_person['email'] = p['email'] updated_person['url'] = p['url'] updated_person['tagline'] = p['tagline'] updated_person['is_disabled'] = p['is_disabled'] updated_person['nyunetid'] = p['nyunetid'] if updated_person is not None: return updated_person else: raise FindError(message="Person does not exist", context="People.editPerson") else: raise DbError(message="Could not update person", context="People.editPerson", dberror="") else: raise ValidationError(message="Nothing to update", context="People.editPerson")
def addPerson(forename, surname, location, email, nyunetid, url, tagline, password): if validate_email(email, verify=False) is False: raise SaveError(message="Email address is invalid", context="People.addPerson") if email_domain_is_allowed(email) is False: raise SaveError( message="You cannot register with this email address", context="People.addPerson") # TODO - Enforce password more complex password requirements? if password is not None and (len(password) >= 6): password_hash = sha256_crypt.hash(password) ts = time.time() created_on = datetime.datetime.fromtimestamp(ts).strftime( '%Y-%m-%d %H:%M:%S') try: result = db.run( "MATCH (n:Person{email: {email}}) RETURN ID(n) as id, n.surname as surname, n.forename AS forename, n.email as email, n.nyunetid as nyunetid", { "email": email }).peek() except Exception as e: raise DbError(message="Could not look up user", context="People.addPerson", dberror=e.message) if result: raise SaveError( message="User already exists with this email address", context="People.addPerson") # return { # "exists": True, # "user_id": result['id'], # "surname": result['surname'], # "forename": result['forename'], # "name": str(result['forename']) + " " + str(result['surname']), # "email": result['email'], # "nyunetid": result['nyunetid'] # } else: try: result = db.run( "CREATE (n:Person {url: {url}, surname: {surname}, forename: {forename}, email: {email}, location: {location}, tagline: {tagline}, nyunetid: {nyunetid}, is_disabled: 0, is_admin: 0," + "password: {password_hash}, created_on: {created_on}, prefs: ''})" + " RETURN n.forename AS forename, n.surname AS surname, n.location AS location, n.email AS email, n.url AS url, n.tagline AS tagline, n.nyunetid as nyunetid, ID(n) AS user_id", { "url": url, "surname": surname, "forename": forename, "email": email, "location": location, "tagline": tagline, "nyunetid": nyunetid, "password_hash": password_hash, "created_on": created_on }) except Exception as e: raise DbError(message="Could not create user", context="People.addPerson", dberror=e.message) if result: person = {} for p in result: person['surname'] = p['surname'] person['forename'] = p['forename'] person['name'] = str(p['forename']) + " " + str( p['surname']) person['location'] = p['location'] person['email'] = p['email'] person['nyunetid'] = p['nyunetid'] person['url'] = p['url'] person['tagline'] = p['tagline'] person['user_id'] = p['user_id'] send_mail( p['email'], None, "Registration notification", "registration", { "email": p['email'], "login_url": app_config["base_url"] }) return person else: raise SaveError(message="Could not add person", context="People.addPerson") raise SaveError( message="Password must be at least six characters in length", context="People.addPerson")
def getInfoForList(repo_id, code): repo_id = int(repo_id) try: code = int(code) except ValueError: pass try: if isinstance(code, int): list_res = db.run( "MATCH (r:Repository)--(l:List) WHERE ID(l) = {code} AND ID(r) = {repo_id} RETURN ID(l) as id, l.name as name, l.code as code, l.description as description, l.merge_allowed as merge_allowed", { "code": code, "repo_id": repo_id }).peek() if list_res is None: return None items_res = db.run( "MATCH (i:ListItem)--(l:List)--(r:Repository) WHERE ID(l) = {code} AND ID(r) = {repo_id} RETURN ID(i) as id, i.display as display, i.code as code, i.description as description", { "code": code, "repo_id": repo_id }) else: list_res = db.run( "MATCH (r:Repository)--(l:List) WHERE l.code = {code} AND ID(r) = {repo_id} RETURN ID(l) as id, l.name as name, l.code as code, l.description as description, l.merge_allowed as merge_allowed", { "code": code, "repo_id": repo_id }).peek() if list_res is None: return None items_res = db.run( "MATCH (i:ListItem)--(l:List)--(r:Repository) WHERE l.code = {code} AND ID(r) = {repo_id} RETURN ID(i) as id, i.display as display, i.code as code, i.description as description", { "code": code, "repo_id": repo_id }) info = { 'list_id': list_res['id'], 'name': list_res['name'], 'code': list_res['code'], 'description': list_res['description'], 'merge_allowed': list_res['merge_allowed'] } item_list = [] if items_res: for r in items_res: li = { 'id': r['id'], 'display': r['display'], 'code': r['code'], 'description': r['description'] } item_list.append(li) info['items'] = item_list return info except Exception as e: raise DbError(message="Could not get list items for list", context="List.getInfoForList", dberror=e.message)
def editList(repo_id, list_id, name, code, description, items, delete_items, merge_setting): try: repo_id = int(repo_id) list_id = int(list_id) except TypeError: raise DbError(message="Invalid repo_id or list_id provided", context="List.addListItem", dberror="") result = db.run( "MATCH (r:Repository)--(l:List) WHERE ID(r) = {repo_id} AND ID(l) = {list_id} SET l.name = {name}, l.code = {code}, l.description = {description}, l.merge_allowed = {merge} RETURN ID(l) AS id", { "repo_id": int(repo_id), "list_id": int(list_id), "name": name, "code": code, "description": description, "merge": merge_setting }) # add/edit fields item_status = {} for k in items: if 'id' in items[k]: # edit existing field li_ret = ListManager.editListItem(repo_id, code, items[k].get('id', ''), items[k].get('display', ''), items[k].get('code', ''), items[k]['description']) if 'item_id' in li_ret: item_status[items[k]['code']] = { 'status_code': 200, 'item_id': li_ret['item_id'], 'msg': 'Edited list item' } else: item_status[items[k]['code']] = { 'status_code': 200, 'item_id': None, 'msg': 'Could not edit list item' } else: # add field li_ret = ListManager.addListItem( repo_id, code, items[k].get('display', ''), items[k].get('code', ''), items[k].get('description', '')) if 'item_id' in li_ret: item_status[items[k]['code']] = { 'status_code': 200, 'item_id': li_ret['item_id'], 'msg': 'Created new list item' } else: item_status[items[k]['code']] = { 'status_code': 200, 'item_id': None, 'msg': 'Could not create new list item' } # delete fields if delete_items: for item_id in delete_items: ListManager.deleteListItem(repo_id, code, item_id) if result: ret = {} for r in result: ret['type'] = { "id": r['id'], "name": name, "code": code, "description": description, "item_status": item_status } return ret else: raise DbError(message="Could not edit list", context="List.editList", dberror="")
def editField(repo_id, typecode, field_id, name, code, fieldtype, description, settings): if code is None or len(code) == 0: raise ValidationError(message="Field code is required", context="Schema.editField") if name is None or len(name) == 0: raise ValidationError(message="Field name is required", context="Schema.editField") ret = {} # Check field type if fieldtype not in SchemaManager.getDataTypes(): raise ValidationError(message="Invalid field type " + fieldtype, context="Schema.editField") ft = SchemaManager.getDataTypeInstance(fieldtype) if ft is None: raise ValidationError(message="Invalid field type " + fieldtype, context="Schema.editField") sv = ft.validateSettings(settings) if sv is not True: raise SettingsValidationError( message="Invalid settings for field " + name, errors={code: sv}, context="Schema.editField") # TODO: check that repository is owned by current user SchemaManager.resetTypeInfoCache() result = db.run( "MATCH (f:SchemaField {code: {code}})--(t:SchemaType {code: {typecode}})--(r:Repository) WHERE ID(r) = {repo_id} AND ID(f) <> {field_id} RETURN ID(f) as id, f.name as name", { "typecode": typecode, "code": code, "repo_id": int(repo_id), "field_id": int(field_id) }).peek() if result is not None: ret['msg'] = "Field already exists" ret['field_id'] = result['id'] ret['name'] = result['name'] return ret else: flds = [ "f.name = {name}", "f.code = {code}", "f.description = {description}", "f.type = {fieldtype}" ] params = { "repo_id": int(repo_id), "name": name, "code": code, "description": description, "typecode": typecode, "fieldtype": fieldtype, "field_id": int(field_id) } for s in settings: flds.append("f.settings_" + s + " = {settings_" + s + "}") params["settings_" + s] = settings[s] if fieldtype == 'ListDataType': field_info = SchemaManager.getInfoForField( repo_id, typecode, field_id) print field_info, settings if 'settings_list_code' not in field_info: field_info['list_code'] = settings['list_code'] field_info['settings_list_code'] = settings['list_code'] if settings['list_code'] != field_info['settings_list_code']: from lib.managers.DataManager import DataManager from lib.managers.ListManager import ListManager schema_data = DataManager.getDataForType(repo_id, typecode) list_data = ListManager.getInfoForList( repo_id, settings['list_code']) list_items = [li['display'] for li in list_data['items']] for data in schema_data['data']: if code not in data: continue list_entry = data[code] if not list_data['merge_allowed'] or list_data[ 'merge_allowed'] != 0: if list_entry not in list_items: data[code] = None DataManager.update(data['id'], data) else: if list_entry in list_items: continue list_entry_code = item_code = re.sub( r'[^A-Za-z0-9_]+', '_', list_entry).lower() ListManager.addListItem(repo_id, settings['list_code'], list_entry, list_entry_code) result = db.run( "MATCH (r:Repository)--(t:SchemaType {code: {typecode}})--(f:SchemaField) WHERE ID(r) = {repo_id} AND ID(f) = {field_id} SET " + ", ".join(flds) + " RETURN ID(f) as id, f.name as name", params) r = result.peek() # TODO: check query result if r: ret['field_id'] = r['id'] ret['name'] = r['name'] return ret else: raise DbError(message="Could not edit field", context="Schema.editField", dberror="")