def testList(self): cats = [] for i in range(0, 3): s = ParaObject(self.catsType + str(i)) s.type = self.catsType cats.append(s) self.pc.createAll(cats) sleep(1) self.assertIs(len(self.pc.list(None)), 0) self.assertIs(len(self.pc.list("")), 0) list1 = self.pc.list(self.catsType) self.assertIsNot(len(list1), 0) self.assertEqual(3, len(list1)) self.assertEqual(isinstance(list1[0], ParaObject), True) list2 = self.pc.list(self.catsType, Pager(limit=2)) self.assertIsNot(len(list2), 0) self.assertEqual(2, len(list2)) nl = [cats[0].id, cats[1].id, cats[2].id] self.pc.deleteAll(nl) self.assertIs(self.catsType in self.pc.getApp()["datatypes"].values(), True)
def getEntity(res: Response, returnRawJSON: bool = True): """ Deserializes a Response object to POJO of some type. @param res: response @param returnRawJSON: true if an array should be returned @return: an object """ if res: code = res.status_code if code == 200 or code == 201 or code == 304: if returnRawJSON: try: body = res.json() return body if body else {} except JSONDecodeError: return res.text else: obj = ParaObject() obj.setFields(res.json()) return obj elif code != 404 or code != 304 or code != 204: error = res.json() if error and error["code"]: msg = (error["message"] if error["message"] else "error") logging.error(msg + " - " + error["code"]) else: logging.error(code + " - " + res.reason) return None
def signIn(self, provider: str, providertoken: str, rememberjwt: bool = True): """ Takes an identity provider access token and fetches the user data from that provider. A new User object is created if that user doesn't exist. Access tokens are returned upon successful authentication using one of the SDKs from Facebook, Google, Twitter, etc. <b>Note:</b> Twitter uses OAuth 1 and gives you a token and a token secret. <b>You must concatenate them like this: <code>{oauth_token}:{oauth_token_secret}</code> and use that as the provider access token.</b> @param provider: identity provider, e.g. 'facebook', 'google'... @param providertoken: access token from a provider like Facebook, Google, Twitter @param rememberjwt: it true the access token returned by Para will be stored locally and available through getAccessToken(). True by default. @return: a User object or None if something failed """ if not provider or not providertoken: return None credentials = {"appid": self.__accessKey, "provider": provider, "token": providertoken} result = self.getEntity(self.invokePost(self.JWT_PATH, json.dumps(credentials))) if result and result["user"] and result["jwt"]: jwt_data = result["jwt"] if rememberjwt: self.__tokenKey = jwt_data["access_token"] self.__tokenKeyExpires = jwt_data["expires"] self.__tokenKeyNextRefresh = jwt_data["refresh"] obj = ParaObject() obj.setFields(result["user"]) return obj else: self.clearAccessToken() return None
def update(self, obj: ParaObject): """ Updates an object permanently. Supports partial updates. @param obj: the object to update @return: updated object """ if not obj: return None return self.getEntity(self.invokePatch(obj.getObjectURI(), obj.jsonSerialize()), False)
def testGetObjectURI(self): o1 = ParaObject() self.assertEqual(o1.getObjectURI(), "/sysprop") o1.type = "dog" self.assertEqual(o1.getObjectURI(), "/dog") o1.id = "123" self.assertEqual(o1.getObjectURI(), "/dog/123") o2 = ParaObject(id_="123 56", type_="dog 2") self.assertEqual(o2.getObjectURI(), "/dog%202/123%2056")
def create(self, obj: ParaObject): """ Persists an object to the data store. If the object's type and id are given, then the request will be a {@code PUT} request and any existing object will be overwritten. @param obj: the domain object @return: the same object with assigned id or null if not created. """ if not obj: return None if obj.id and obj.type: return self.getEntity(self.invokePut(obj.getObjectURI(), obj.jsonSerialize()), False) else: return self.getEntity(self.invokePost(self.urlenc(obj.type), obj.jsonSerialize()), False)
def getItemsFromList(result: list): """ Deserializes ParaObjects from a JSON array (the "items:[]" field in search results). @param result: a list of deserialized objects @return: a list of ParaObjects """ if result and len(result) > 0: # this isn't very efficient but there's no way to know what type of objects we're reading objects = [] for obj in result: if obj and len(obj) > 0: p = ParaObject() p.setFields(obj) objects.append(p) return objects return []
def delete(self, obj: ParaObject): """ Deletes an object permanently. @param obj: the object """ if obj: self.invokeDelete(obj.getObjectURI())
def getChildren(self, obj: ParaObject, type2: str, field: str, term: str, pager: Pager = None): """ Returns all child objects linked to this object. @param obj: the object to execute this method on @param type2: the type of children to look for @param field: the field name to use as filter @param term: the field value to use as filter @param pager: a Pager @return: a list of ParaObject in a one-to-many relationship with this object """ if not obj or not obj.id or not type2: return [] params = self.pagerToParams(pager) params["childrenonly"] = "true" if field: params["field"] = field if term: params["term"] = term url = obj.getObjectURI() + "/links/" + self.urlenc(type2) return self.getItems(self.getEntity(self.invokeGet(url, params)), pager=pager)
def testMisc(self): types = self.pc.types() self.assertIsNotNone(types) self.assertIsNot(len(types), 0) self.assertIs(ParaObject(None, "user").type in types.values(), True) self.assertEqual("app:test", self.pc.me().id)
def deleteChildren(self, obj: ParaObject, type2: str): """ Deletes all child objects permanently. @param obj: the object to execute this method on @param type2: the children's type. """ params = {"childrenonly": "true"} url = obj.getObjectURI() + "/links/" + self.urlenc(type2) self.invokeDelete(url, params)
def testValidationConstraints(self): # Validations string kittenType = "kitten" constraints = self.pc.validationConstraints() self.assertIsNot(len(constraints), 0) self.assertIs("app" in constraints.keys(), True) self.assertIs("user" in constraints.keys(), True) constraint = self.pc.validationConstraints("app") self.assertIsNot(len(constraint), 0) self.assertIs("app" in constraint.keys(), True) self.assertEqual(1, len(constraint)) self.pc.addValidationConstraint(kittenType, "paws", Constraint.required()) constraint = self.pc.validationConstraints(kittenType) self.assertIs("paws" in constraint[kittenType].keys(), True) ct = ParaObject("felix") ct.type = kittenType # validation fails ct2 = self.pc.create(ct) self.assertIsNone(ct2) ct["paws"] = "4" self.assertIsNotNone(self.pc.create(ct)) self.pc.removeValidationConstraint(kittenType, "paws", "required") constraint = self.pc.validationConstraints(kittenType) self.assertIs(kittenType in constraint.keys(), False) # votes self.assertIs(self.pc.voteUp(ct, self.u.id), True) self.assertIsNot(self.pc.voteUp(ct, self.u.id), True) self.assertIs(self.pc.voteDown(ct, self.u.id), True) self.assertIs(self.pc.voteDown(ct, self.u.id), True) self.assertIsNot(self.pc.voteDown(ct, self.u.id), True) self.pc.delete(ct) self.pc.delete(ParaObject("vote:" + self.u.id + ":" + ct.id, "vote")) self.assertIs(self.pc.getServerVersion().startswith("1"), True) self.assertNotEqual("unknown", self.pc.getServerVersion())
def testSetFields(self): o1 = ParaObject("123", "dog") o1.one = 1 o1.two = "two" assert o1.type == "dog" assert o1.id == "123" obj = json.loads(o1.jsonSerialize()) obj1 = ParaObject() obj1.setFields(obj) assert obj1.type == "dog" assert obj1.id == "123" assert obj1.two == "two"
def unlinkAll(self, obj: ParaObject): """ Unlinks all objects that are linked to this one. Deletes all Linker objects. Only the links are deleted. Objects are left untouched. @param obj: the object to execute this method on """ if not obj or not obj.id: return url = obj.getObjectURI() + "/links" self.invokeDelete(url)
def setUpClass(cls): cls.pc = ParaClient( "app:test", "Yi/b6Bw6dCFWBqHiExNUwqqT/UoUf8NuWbwOcxe7ddKuqF9luUxagA==") cls.pc.setEndpoint("http://localhost:8080") cls.pc2 = ParaClient("app:test", "") cls.pc2.setEndpoint("http://localhost:8080") if not cls.pc.me(): raise Exception( "Local Para server must be started before testing.") cls.u = ParaObject("111") cls.u.name = "John Doe" cls.u.tags = ["one", "two", "three"] cls.u1 = ParaObject("222") cls.u1.name = "Joe Black" cls.u1.tags = ["two", "four", "three"] cls.u2 = ParaObject("333") cls.u2.name = "Ann Smith" cls.u2.tags = ["four", "five", "three"] cls.t = ParaObject("tag:test", "tag") cls.t["count"] = 3 cls.t["tag"] = "test" cls.a1 = ParaObject("adr1", "address") cls.a1.name = "Place 1" cls.a1["address"] = "NYC" cls.a1["country"] = "US" cls.a1["latlng"] = "40.67,-73.94" cls.a1.parentid = cls.u.id cls.a1.creatorid = cls.u.id cls.a2 = ParaObject("adr2", "address") cls.a2.name = "Place 2" cls.a2["address"] = "NYC" cls.a2["country"] = "US" cls.a2["latlng"] = "40.69,-73.95" cls.a2.parentid = cls.t.id cls.a2.creatorid = cls.t.id cls.s1 = ParaObject("s1") cls.s1[ "text"] = "This is a little test sentence. Testing, one, two, three." cls.s2 = ParaObject("s2") cls.s2[ "text"] = "We are testing this thing. This sentence is a test. One, two." cls.pc.createAll( [cls.u, cls.u1, cls.u2, cls.t, cls.s1, cls.s2, cls.a1, cls.a2])
def voteDown(self, obj: ParaObject, voterid: str): """ Downvote an object and register the vote in DB. @param obj: the object to receive -1 votes @param voterid: the userid of the voter @return: true if vote was successful """ if not obj or not voterid: return False res = self.getEntity(self.invokePatch(obj.getObjectURI(), json.dumps({"_votedown": voterid}))) return True if res else False
def unlink(self, obj: ParaObject, type2: str, id2: str): """ Unlinks an object from this one. Only a link is deleted. Objects are left untouched. @param obj: the object to execute this method on @param type2: the other type @param id2: the other id """ if not obj or not obj.id or not type2 or not id2: return url = obj.getObjectURI() + "/links/" + self.urlenc(type2) + "/" + self.urlenc(id2) self.invokeDelete(url)
def getLinkedObjects(self, obj: ParaObject, type2: str, pager: Pager = None): """ Returns all objects linked to the given one. Only applicable to many-to-many relationships. @param obj: the object to execute this method on @param type2: type of linked objects to search for @param pager: a Pager @return: a list of linked objects """ if not obj or not obj.id or not type2: return [] url = obj.getObjectURI() + "/links/" + self.urlenc(type2) return self.getItems(self.getEntity(self.invokeGet(url, self.pagerToParams(pager))), pager=pager)
def countLinks(self, obj: ParaObject, type2: str): """ Count the total number of links between this object and another type of object. @param obj: the object to execute this method on @param type2: the other type of object @return: the number of links for the given object """ if not obj or not obj.id or not type2: return 0 pager = Pager() url = obj.getObjectURI() + "/links/" + self.urlenc(type2) self.getItems(self.getEntity(self.invokeGet(url, {"count": "true"})), pager=pager) return pager.count
def link(self, obj: ParaObject, id2: str): """ Links an object to this one in a many-to-many relationship. Only a link is created. Objects are left untouched. The type of the second object is automatically determined on read. @param obj: the object to execute this method on @param id2: link to the object with this id @return: the id of the Linker object that is created """ if not obj or not obj.id or not id2: return url = obj.getObjectURI() + "/links/" + self.urlenc(id2) return self.getEntity(self.invokePost(url))
def isLinked(self, obj: ParaObject, type2: str, id2: str): """ Checks if this object is linked to another. @param obj: the object to execute this method on @param type2: type of linked objects to search for @param id2: the other id @return: true if the two are linked """ if not obj or not obj.id or not type2 or not id2: return False url = obj.getObjectURI() + "/links/" + self.urlenc(type2) + "/" + self.urlenc(id2) res = self.getEntity(self.invokeGet(url)) return True if res else False
def countChildren(self, obj: ParaObject, type2: str): """ Count the total number of child objects for this object. @param obj: the object to execute this method on @param type2: the type of the other object @return: the number of links """ if not obj or not obj.id or not type2: return 0 params = {"count": "true", "childrenonly": "true"} pager = Pager() url = obj.getObjectURI() + "/links/" + self.urlenc(type2) self.getItems(self.getEntity(self.invokeGet(url, params)), pager=pager) return pager.count
def findChildren(self, obj: ParaObject, type2: str, query: str, pager: Pager = None): """ Search through all child objects. Only searches child objects directly connected to this parent via the {@code parentid} field. @param obj: the object to execute this method on @param type2: the type of children to look for @param query: a query string @param pager: a Pager @return: a list of ParaObject in a one-to-many relationship with this object """ if not obj or not obj.id or not type2: return [] params = self.pagerToParams(pager) params["childrenonly"] = "true" params["q"] = query url = obj.getObjectURI() + "/links/" + self.urlenc(type2) return self.getItems(self.getEntity(self.invokeGet(url, params)), pager=pager)
def findLinkedObjects(self, obj: ParaObject, type2: str, field: str = "name", query: str = "*", pager: Pager = None): """ Searches through all linked objects in many-to-many relationships. @param obj: the object to execute this method on @param type2: type of linked objects to search for @param field: the name of the field to target (within a nested field "nstd") @param query: a query string @param pager: a Pager @return: a list of linked objects """ if not obj or not obj.id or not type2: return [] params = self.pagerToParams(pager) params["field"] = field params["q"] = query url = obj.getObjectURI() + "/links/" + self.urlenc(type2) return self.getItems(self.getEntity(self.invokeGet(url, params)), pager=pager)
def testCRUD(self): self.assertIsNotNone(self.pc.create(ParaObject())) t1 = self.pc.create(ParaObject("test1", "tag")) t1["tag"] = "test1" self.assertIsNotNone(t1) self.assertIsNone(self.pc.read(None, None)) self.assertIsNone(self.pc.read("", "")) tr_id = self.pc.read(id_=t1.id) self.assertIsNotNone(tr_id) self.assertIsNotNone(tr_id.timestamp) self.assertEqual(t1.tag, tr_id.tag) tr = self.pc.read(t1.type, t1.id) self.assertIsNotNone(tr) self.assertIsNotNone(tr.timestamp) self.assertEqual(t1["tag"], tr["tag"]) tr["count"] = 15 tu = self.pc.update(tr) self.assertIsNone(self.pc.update(ParaObject("None"))) self.assertIsNotNone(tu) self.assertEqual(tu["count"], tr["count"]) self.assertIsNotNone(tu.updated) s = ParaObject() s.type = self.dogsType s["foo"] = "bark!" s = self.pc.create(s) dog = self.pc.read(self.dogsType, s.id) self.assertIsNotNone(dog["foo"]) self.assertEqual("bark!", dog["foo"]) self.pc.delete(t1) self.pc.delete(dog) self.assertIsNone(self.pc.read(tr.type, tr.id))
def testBatchCRUD(self): dogs = [] for i in range(0, 3): s = ParaObject() s.type = self.dogsType s["foo"] = "bark!" dogs.append(s) self.assertIs(len(self.pc.createAll(None)), 0) l1 = self.pc.createAll(dogs) self.assertEqual(3, len(l1)) self.assertIsNotNone(l1[0].id) self.assertIs(len(self.pc.readAll(None)), 0) nl = [] self.assertIs(len(self.pc.readAll(nl)), 0) nl.append(l1[0].id) nl.append(l1[1].id) nl.append(l1[2].id) l2 = self.pc.readAll(nl) self.assertEqual(3, len(l2)) self.assertEqual(l1[0].id, l2[0].id) self.assertEqual(l1[1].id, l2[1].id) self.assertIsNotNone(l2[0]["foo"]) self.assertEqual("bark!", l2[0]["foo"]) self.assertIs(len(self.pc.updateAll(None)), 0) part1 = ParaObject(l1[0].id) part2 = ParaObject(l1[1].id) part3 = ParaObject(l1[2].id) part1.type = self.dogsType part2.type = self.dogsType part3.type = self.dogsType part1["custom"] = "prop" part1.name = "NewName1" part2.name = "NewName2" part3.name = "NewName3" l3 = self.pc.updateAll([part1, part2, part3]) self.assertIsNotNone(l3[0]["custom"]) self.assertEqual(self.dogsType, l3[0].type) self.assertEqual(self.dogsType, l3[1].type) self.assertEqual(self.dogsType, l3[2].type) self.assertEqual(part1.name, l3[0].name) self.assertEqual(part2.name, l3[1].name) self.assertEqual(part3.name, l3[2].name) self.pc.deleteAll(nl) sleep(1) l4 = self.pc.list(self.dogsType) self.assertIs(len(l4), 0) self.assertIs(self.dogsType in self.pc.getApp()["datatypes"].values(), True)