def getByID(node_id): # TODO: does user have access to this node? try: id = int(node_id) result = db.run( "MATCH (d:Data)--(t:SchemaType)--(r:Repository) WHERE ID(d) = {node_id} RETURN d, t.name as typename, t.code as typecode, ID(t) as schema_id, ID(r) as repo_id", {"node_id": id}) except: result = db.run( "MATCH (d:Data)--(t:SchemaType)--(r:Repository) WHERE d.uuid = {uuid} RETURN d, ID(d) as node_id, t.name as typename, t.code as typecode, ID(t) as schema_id, ID(r) as repo_id", {"uuid": node_id}) if result.peek(): for r in result: return { "node_id": r["node_id"], "typename": r["typename"], "typecode": r["typecode"], "schema_id": r["schema_id"], "repo_id": r["repo_id"], "data": r["d"].properties } else: raise FindError(message="Node does not exist")
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 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 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 delete(repo_id): RepoManager.validate_repo_id(repo_id) owner = RepoManager.getOwner(repo_id) result = db.run( "MATCH (n:Repository) WHERE ID(n) = {repo_id} WITH n OPTIONAL MATCH (n)--(s:SchemaType)--(f:SchemaField) WITH n, s, f OPTIONAL MATCH (s)--(d:Data) DETACH DELETE n, s, f, d", {"repo_id": repo_id}) summary = result.consume() # Was this the only repo for that owner? if "id" in owner: repos = lib.managers.PeopleManager.PeopleManager.getRepos( owner["id"]) if len(repos) == 0: # create new default repo because user just deleted their only one. RepoManager.create( app_config['default_repo_information']['url'], app_config['default_repo_information']['name'], app_config['default_repo_information']['description'], app_config['default_repo_information']['license'], 0, owner['id'], "ID(p) = {identity}") if summary.counters.nodes_deleted >= 1: return True raise FindError(message="Could not find repository", context="Repositories.delete")
def getReposForPerson(identity): repos = PeopleManager.getRepos(identity) user = PeopleManager.getInfo(identity) if repos is not None: return {"repos": repos, "userinfo": user} raise FindError(message="Could not find person", context="People.getReposForPerson")
def checkRepoPermissions(user_name, repo_id): repo_list = PeopleManager.getRepoIDs(user_name) print repo_list, repo_id try: repo_id = int(repo_id) except: raise FindError(message="Need integer repo_id", context="People.checkRepoPermissions") if repo_id in repo_list: return True return False
def getRepoForPortal(repo_uuid): try: result = db.run( "MATCH (r:Repository {uuid: {uuid}}) RETURN ID(r) AS id, r.name as name, r.readme as description", { "uuid": repo_uuid }).peek() if result: repo_id = result['id'] name = result['name'] description = result['description'] except: raise FindError("Could not load repository with UUID") repo_owner = RepoManager.getOwner(repo_id) owner_name = repo_owner['name'] owner_location = repo_owner['location'] owner_tagline = repo_owner['tagline'] data = RepoManager.getData(repo_id, 48) return { "repo": repo_id, "repo_name": name, "description": description, "data": data, "owner": owner_name, "location": owner_location, "tagline": owner_tagline } # # ADMIN ONLY # Set a repository to be featured @staticmethod def setFeaturedRepo(repo_id, featured): RepoManager.validate_repo_id(repo_id) if int(featured) != 0 and int(featured) != 1: featured = 0 result = db.run( "MATCH (r:Repository) WHERE ID(r)={repo_id} SET r.published = {featured} RETURN ID(r), r.featured as featured", { "repo_id": int(repo_id), "featured": featured }).peek() if result: if result['featured'] == featured: return True return False
def removeFollower(repo_id, person_id): RepoManager.validate_repo_id(repo_id) result = db.run( "START p=node(*) MATCH (p)-[rel:FOLLOWS]->(n) WHERE ID(p)={person_id} AND ID(n)={repo_id} DELETE rel", { "person_id": person_id, "repo_id": repo_id }) summary = result.consume() if summary.counters.relationship_deleted >= 1: return True raise FindError(message="Could not find person", context="Repositories.removeFollower")
def getRepositoryByCode(code): result = db.run( "MATCH (r:Repository {name: {code}}) RETURN ID(r) AS id, r.name AS name", {"code": code}) ret = {} if result: for r in result: ret['repo_id'] = r['id'] ret['name'] = r['name'] return ret else: raise FindError("Could not find repository") return ret
def addFollower(repo_id, person_id): RepoManager.validate_repo_id(repo_id) result = db.run( "MATCH (n:Repository) WHERE ID(n)={repo_id} MATCH (p:Person) WHERE ID(p)={person_id} MERGE (p)-[:FOLLOWS]->(n)", { "repo_id": repo_id, "person_id": person_id }) summary = result.consume() if summary.counters.relationships_created >= 1: return True raise FindError(message="Could not find person or repository", context="Repositories.addFollower")
def addCollaborator(repo_id, person_id, access="read-only"): RepoManager.validate_repo_id(repo_id) result = db.run( "MATCH (n:Repository) WHERE ID(n)={repo_id} MATCH (p:Person) WHERE ID(p)={person_id} MERGE (p)-[x:COLLABORATES_WITH]->(n) ON CREATE SET x.access = {access}", { "repo_id": repo_id, "person_id": person_id, "access": access }) summary = result.consume() if summary.counters.relationships_created >= 1: return True raise FindError(message="Already exists", context="Repositories.addCollaborator")
def deleteOwner(repo_id, owner_id): RepoManager.validate_repo_id(repo_id) result = db.run( "START p=node(*) MATCH (p)-[rel:OWNED_BY]->(n) WHERE ID(p)={owner_id} AND ID(n)={repo_id} DELETE rel", { "owner_id": owner_id, "repo_id": repo_id }) summary = result.consume() if summary.counters.relationships_deleted >= 1: return True raise FindError(message="Could not find person or repository", context="Repositories.deleteOwner")
def setOwner(repo_id, identity, ident_str): RepoManager.validate_repo_id(repo_id) result = db.run( "MATCH (n:Repository) WHERE ID(n)={repo_id} MATCH (p:Person) WHERE " + ident_str + " MERGE (p)<-[:OWNED_BY]->(n)", { "repo_id": repo_id, "identity": identity }) summary = result.consume() if summary.counters.relationships_created >= 1: return True else: raise FindError(message="Could not find person", context="Repositories.setOwner")
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 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 setPassword(person_id, password): # TODO: verify user has access to update password... if password is not None: if is_number(person_id): find_str = "ID(p)={person_id}" else: find_str = "p.password_reset_key = {person_id}" db_password_hash = '' # check if password matches person_id result = db.run( "MATCH (p:Person) WHERE " + find_str + " RETURN p.password AS password", {"person_id": person_id}) for p in result: db_password_hash = p['password'] if db_password_hash != '': # hash new password and update DB new_pass_hash = sha256_crypt.hash(password) if db_password_hash == new_pass_hash: return True result = db.run( "MATCH (p:Person) WHERE " + find_str + " SET p.password = {new_pass_hash}, p.password_reset_key = '' RETURN p", { "person_id": person_id, "new_pass_hash": new_pass_hash }) # Check we updated something summary = result.consume() if summary.counters.properties_set >= 1: return True return False else: raise FindError("No user found") else: raise AuthError("Password is empty")
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 _validateData(repo_id, type_code, data, fields_created=None): type_info = SchemaManager.getInfoForType(repo_id, type_code) if type_info is None: raise FindError("Could not load type info") # gather data data_proc = {} row_errors = [] for f in type_info["fields"]: v = None if f['code'] in data: v = data[f['code']] if v is None and f['id'] in data: v = data[f['id']] # Convert data-as-dict to JSON for serialized storage if isinstance(v, dict): v = json.dumps(v) if v is not None and isinstance(v, unicode) is False: if isinstance( v, basestring ) is False: # force non-string values to string prior to casting to unicode v = str(v) v = unicode(v, errors='replace') if v is not None and v != '': dt = SchemaManager.getDataTypeInstanceForField( repo_id, type_code, f["code"], v) dtv = dt.validate(v) if dtv is not True: row_errors.append(f['code']) continue # Parse the data using the relevant datatype plugin # NOTE: If the datatype parser returns a dict we serialize to Neo4j with properties for each key # in the dict. This allows data types to serialize data across multiple node properties if required. # This is distinct from the case where the caller submits a dict as data. In that case we convert it to # JSON prior to performing any parsing. if f['type'] == 'ListDataType': list_code = f['settings']['list_code'] override_merge = False if fields_created: new_fields = [ x + "_list" for x in fields_created.keys() ] if list_code in new_fields: override_merge = True parsed_value = dt.parse(v, list_code, repo_id, override_merge) if len(parsed_value['rejected_items']) > 0: bad_items = "The following items do not appear in the current list and merges are not allowed: " + ', '.join( parsed_value['rejected_items']) row_errors.append(f['code'] + ' ' + bad_items) else: parsed_value = dt.parse(v) # If a dict is returned we need to stored parsed value in multiple fields if isinstance(parsed_value, dict): data_proc[f['code']] = v for k, v in parsed_value.iteritems(): data_proc[f['code'] + "_" + k] = v else: # simple scalar value is assigned direct data_proc[f['code']] = parsed_value SchemaManager.getDataTypeInstanceForField.reset() else: data_proc[f['code']] = v if len(row_errors) > 0: raise FieldValidationError(message="Data is invalid for " + ", ".join(row_errors), errors=dtv, type=type_info['code'], field=f['code'], value=v, context="DataManager.add") return [data_proc, type_info]
def edit(repo_id, name, url, readme, license, published, featured): if url is None or name is None or readme is None: raise ValidationError(message="Name, URL and README must be set", context="Repositories.edit") if RepoManager.nameCheck(name, repo_id) is False: raise ValidationError(message="Name is in use", context="Repositories.edit") update = [] if name is not None: update.append("n.name = {name}") if url is not None: update.append("n.url = {url}") if readme is not None: update.append("n.readme = {readme}") if featured is not None: update.append("n.featured = {featured}") published_on = None if ((int(published) != 0) and (int(published) != 1)) or published is None: published = 0 elif int(published) == 1: ts = time.time() published_on = datetime.datetime.fromtimestamp(ts).strftime( '%Y-%m-%d %H:%M:%S') update.append("n.published_on = {published_on}") if license not in RepoManager.licenses: license = '' update.append("n.published = {published}") update.append("n.license = {license}") update_str = "%s" % ", ".join(map(str, update)) if update_str: print update_str, featured result = db.run( "MATCH (n:Repository) WHERE ID(n)={repo_id} SET " + update_str + " RETURN n.name AS name, n.url AS url, n.readme AS readme, n.license AS license, n.published AS published, n.featured as featured, n.published_on as published_on, ID(n) AS id", { "repo_id": int(repo_id), "name": name, "url": url, "readme": readme, "published": published, "license": license, "featured": featured, "published_on": published_on }) updated_repo = {} for r in result: print r updated_repo['repo_id'] = r['id'] updated_repo['name'] = r['name'] updated_repo['url'] = r['url'] updated_repo['readme'] = r['readme'] updated_repo['license'] = r['license'] updated_repo['published'] = r['published'] updated_repo['published_on'] = r['published_on'] updated_repo['featured'] = r['featured'] summary = result.consume() if summary.counters.properties_set >= 1: return updated_repo raise FindError(message="Could not find repository", context="Repositories.edit")