def test_instance_feed_is_liked(self): self.add_user(handle='tayne', host=None) self.add_user(handle='paul', host=None) self.add_post(author_id=1, title='1 kissie', body='for the boys') self.add_like(liker_id=2, article_id=1) self.add_post(author_id=1, title='2 kissies', body='for the boys') res = self.instance_feed(n=2, user=2) want0 = database_pb2.PostsEntry( global_id=1, author_id=1, title='1 kissie', body='for the boys', creation_datetime={}, likes_count=1, is_liked=True, ) want1 = database_pb2.PostsEntry( global_id=2, author_id=1, title='2 kissies', body='for the boys', creation_datetime={}, is_liked=False, ) self.assertEqual(len(res.results), 2) self.assertIn(want0, res.results) self.assertIn(want1, res.results)
def test_posts_is_followed(self): self.add_user(handle='tayne', host=None) self.add_user(handle='paul', host=None) self.add_post(author_id=1, title='1 kissie', body='for the boys') self.add_follow(follower_id=2, followed_id=1) self.add_post(author_id=1, title='2 kissies', body='for the boys') self.add_post(author_id=2, title='72 kissies', body='for the noah') res = self.find_post(user=2, author_id=1) want0 = database_pb2.PostsEntry( global_id=1, author_id=1, title='1 kissie', body='for the boys', creation_datetime={}, is_followed=True, ) want1 = database_pb2.PostsEntry( global_id=2, author_id=1, title='2 kissies', body='for the boys', creation_datetime={}, is_followed=True, ) self.assertEqual(len(res.results), 2) self.assertIn(want0, res.results) self.assertIn(want1, res.results)
def _add_ap_id(self, global_id, ap_id): req = database_pb2.PostsRequest( request_type=database_pb2.RequestType.UPDATE, match=database_pb2.PostsEntry(global_id=global_id, ), entry=database_pb2.PostsEntry(ap_id=ap_id, ), ) resp = self._db_stub.Posts(req) if resp.result_type != general_pb2.ResultType.OK: return "Error inserting ap_id into DB: " + str(resp.error) return None
def GetArticle(self, req, context): self._logger.debug( 'Article object requested for id: {} by user: {}'.format( req.article_id, req.username)) user = self._users_util.get_user_from_db(handle=req.username, host_is_null=True) if user is None: self._logger.warning('Could not find user in database.') return actors_pb2.ArticleResponse() actor_url = self._activities_util.build_actor(user.handle, self._host_name) articleEntry = database_pb2.PostsEntry(global_id=req.article_id) article_id = self._activities_util.build_article_ap_id( user, articleEntry) article_url = self._activities_util.build_local_article_url( user, articleEntry) article, err = self._activities_util.get_article_by_ap_id(article_id) if err is not None: self._logger.warning( 'Could not find article in database: {}'.format(err)) self._logger.warning('ArticleId: {}'.format(article_id)) return actors_pb2.ArticleResponse() publish_time = self._activities_util.timestamp_to_rfc( article.creation_datetime) return actors_pb2.ArticleResponse(actor=actor_url, content=article.body, published=publish_time, summary=article.summary, title=article.title, ap_id=article_id, article_url=article_url)
def SendCreate(self, req, context): self._logger.debug("Recieved a new create action.") author = self._users_util.get_user_from_db(global_id=req.author_id) # Insert ActivityPub ID into database. # build author entry from scratch to add host into call ue = database_pb2.UsersEntry(handle=author.handle, host=self._host_name) pe = database_pb2.PostsEntry(global_id=req.global_id) ap_id = self._activ_util.build_article_ap_id(ue, pe) article_url = self._activ_util.build_local_article_url(ue, pe) err = self._add_ap_id(req.global_id, ap_id) if err is not None: self._logger.error("Continuing through error: %s", err) # list of follow objects follow_list = self._users_util.get_follower_list(author.global_id) # remove local users foreign_follows = self._users_util.remove_local_users(follow_list) # go through follow send create activity # TODO (sailslick) make async/ parallel in the future for follower in foreign_follows: self._post_create_req(follower, req, ap_id, author, article_url) resp = general_pb2.GeneralResponse() resp.result_type = general_pb2.ResultType.OK return resp
def test_update_filter_deferred_unset(self): entry = database_pb2.PostsEntry( title="Megolavania", ) d = {'body': lambda entry, comp: ("body" + comp, True)} clause, vals = util.entry_to_update(entry, deferred=d) self.assertIn('title = ?', clause) self.assertIn("Megolavania", vals)
def test_not_equivalent_filter_defaults(self): entry = database_pb2.PostsEntry(title="Despacito") clause, vals = util.not_equivalent_filter(entry, defaults=[('body', 'cool')]) self.assertIn('title IS NOT ""', clause) self.assertIn("AND", clause) self.assertIn('body IS NOT ""', clause) self.assertIn("Despacito", vals) self.assertIn("cool", vals)
def _update_locally(self, article, req): self._logger.info("Sending update request to DB") html_body = md_to_html(self._md, req.body) resp = self._db.Posts(dbpb.PostsRequest( request_type=dbpb.RequestType.UPDATE, match=dbpb.PostsEntry(global_id=article.global_id), entry=dbpb.PostsEntry( title=req.title, body=html_body, md_body=req.body, tags=convert_to_tags_string(req.tags), summary=req.summary, ), )) if resp.result_type != general_pb2.ResultType.OK: self._logger.error("Could not update article: %s", resp.error) return False return True
def test_equivalent_filter_defaults_allow_overwrite(self): entry = database_pb2.PostsEntry(title="Despacito", body="dank") clause, vals = util.equivalent_filter(entry, defaults=[('body', 'cool')]) self.assertIn("title = ?", clause) self.assertIn("AND", clause) self.assertIn("body = ?", clause) self.assertIn("Despacito", vals) self.assertIn("dank", vals) self.assertNotIn("cool", vals)
def test_update_filter_deferred_none_return(self): entry = database_pb2.PostsEntry( title="Megolavania", body="sans is angry", ) d = {'body': lambda entry, comp: ("", util.DONT_USE_FIELD)} clause, vals = util.entry_to_update(entry, deferred=d) self.assertIn('title = ?', clause) self.assertNotIn('body = ?', clause) self.assertNotIn("sans is angry", vals)
def test_update_filter(self): entry = database_pb2.PostsEntry( title="Megolavania", body="sans is angry", ) clause, vals = util.entry_to_update(entry) self.assertIn('title = ?', clause) self.assertIn(', ', clause) self.assertIn('body = ?', clause) self.assertIn("Megolavania", vals) self.assertIn("sans is angry", vals)
def test_equivalent_filter_deferred_default_unset(self): entry = database_pb2.PostsEntry(title="Despacito", ) d = {'body': lambda entry, comp: ("body" + comp, True)} de = [('body', False)] clause, vals = util.equivalent_filter(entry, defaults=de, deferred=d) self.assertIn("title = ?", clause) self.assertIn("AND", clause) self.assertIn("body = ?", clause) self.assertIn("Despacito", vals) self.assertIn(False, vals)
def _get_article(self, article_id): req = database_pb2.PostsRequest( request_type=database_pb2.PostsRequest.FIND, match=database_pb2.PostsEntry(global_id=article_id, ), ) self._logger.info("Sending request to DB for article %d", article_id) resp = self._db.Posts(req) if resp.result_type == database_pb2.PostsResponse.ERROR: return None, resp.error elif len(resp.results) != 1: return None, "Expected 1 result, got " + str(len(resp.results)) return resp.results[0], None
def _get_article(self, article_id): posts_req = dbpb.PostsRequest( request_type=dbpb.RequestType.FIND, match=dbpb.PostsEntry(global_id=article_id, ), ) find_resp = self._db.Posts(posts_req) if find_resp.result_type != general_pb2.ResultType.OK: raise SendUndoException(find_resp.error) elif len(find_resp.results) != 1: raise SendUndoException("Expecting 1 result, got {}".format( len(find_resp.results))) return find_resp.results[0]
def ReceiveUpdateActivity(self, req, ctx): self._logger.info("Received edit for article '%s'", req.title) html_body = md_to_html(self._md, req.body) resp = self._db.Posts( dbpb.PostsRequest( request_type=dbpb.PostsRequest.UPDATE, match=dbpb.PostsEntry(ap_id=req.ap_id), entry=dbpb.PostsEntry( title=req.title, body=html_body, md_body=req.body, summary=req.summary, ), )) if resp.result_type != dbpb.PostsResponse.OK: self._logger.error("Could not update article: %s", resp.error) return upb.UpdateResponse( result_type=upb.UpdateRespones.ERROR, error="Error updating article in DB", ) return upb.UpdateResponse(result_type=upb.UpdateResponse.OK)
def _get_shared_article(self, article_id): posts_req = database_pb2.PostsRequest( request_type=database_pb2.RequestType.FIND, match=database_pb2.PostsEntry(global_id=article_id, ), ) resp = self._db.Posts(posts_req) if resp.result_type != general_pb2.ResultType.OK: return None, resp.error elif len(resp.results) > 1: return None, "Recieved too many results from DB" elif len(resp.results) == 0: return None, "No matching DB entry for this article" return resp.results[0], None
def test_instance_feed_is_followed(self): self.add_user(handle='tayne', host=None) self.add_user(handle='paul', host=None) self.add_user(handle='rudd', host=None) self.add_post(author_id=1, title='1 kissie', body='for the boys') self.add_follow(follower_id=2, followed_id=1) self.add_post(author_id=1, title='2 kissies', body='for the boys') self.add_post(author_id=3, title='3 kissies', body='for the boys') res = self.instance_feed(n=3, user=2) want0 = database_pb2.PostsEntry( global_id=1, author_id=1, title='1 kissie', body='for the boys', creation_datetime={}, is_followed=True, ) want1 = database_pb2.PostsEntry( global_id=2, author_id=1, title='2 kissies', body='for the boys', creation_datetime={}, is_followed=True, ) want2 = database_pb2.PostsEntry( global_id=3, author_id=3, title='3 kissies', body='for the boys', creation_datetime={}, is_followed=False, ) self.assertEqual(len(res.results), 3) self.assertIn(want0, res.results) self.assertIn(want1, res.results) self.assertIn(want2, res.results)
def add_post(self, author_id=None, title=None, body=None): post_entry = database_pb2.PostsEntry( author_id=author_id, title=title, body=body, ) req = database_pb2.PostsRequest( request_type=database_pb2.RequestType.INSERT, entry=post_entry, ) add_res = self.posts.Posts(req, self.ctx) self.assertNotEqual(add_res.result_type, general_pb2.ResultType.ERROR) return add_res
def test_posts_no_filter(self): self.add_user(handle='tayne', host=None) # local user, id 1 self.add_user(handle='tayne2', host=None) # local user, id 2 self.add_post(author_id=1, title='1 kissie', body='for the boys') self.add_post(author_id=1, title='2 kissies', body='for the boys') res = self.find_post(user=2) want0 = database_pb2.PostsEntry( global_id=1, author_id=1, title='1 kissie', body='for the boys', creation_datetime={}, ) want1 = database_pb2.PostsEntry( global_id=2, author_id=1, title='2 kissies', body='for the boys', creation_datetime={}, ) self.assertEqual(len(res.results), 2) self.assertIn(want0, res.results) self.assertIn(want1, res.results)
def test_limit_works_in_instance_feed(self): self.add_user(handle='tayne', host=None) # local user, id 1 self.add_post(author_id=1, title='1 kissie', body='for the boys') self.add_post(author_id=1, title='2 kissies', body='for the boys') self.add_post(author_id=1, title='3 kissies', body='for the boys') res = self.instance_feed(2) want0 = database_pb2.PostsEntry( global_id=2, author_id=1, title='2 kissies', body='for the boys', creation_datetime={}, ) want1 = database_pb2.PostsEntry( global_id=3, author_id=1, title='3 kissies', body='for the boys', creation_datetime={}, ) self.assertEqual(len(res.results), 2) self.assertIn(want0, res.results) self.assertIn(want1, res.results)
def test_equivalent_filter_deferred(self): entry = database_pb2.PostsEntry( title="Despacito", body="alexa", ) d = {'body': lambda entry, comp: ("body" + comp, True)} clause, vals = util.equivalent_filter(entry, deferred=d) self.assertIn("title = ?", clause) self.assertIn("AND", clause) self.assertIn("body = ?", clause) self.assertIn("Despacito", vals) self.assertIn(True, vals) self.assertNotIn("alexa", vals)
def delete_article(logger, db, global_id=None, ap_id=None): """ Deletes an article from the database safely (removing all references). Returns True on success and False on error. """ logger.info("Deleting post global_id: %s, ap_id: %s", global_id, ap_id) resp = db.SafeRemovePost( database_pb2.PostsEntry( global_id=global_id, ap_id=ap_id, )) if resp.result_type != general_pb2.ResultType.OK: logger.error("Error deleting from DB: %s", resp.error) return False return True
def test_no_foreign_posts_in_instance_feed(self): self.add_user(handle='tayne', host=None) # local user, id 1 self.add_user(handle='nude_tayne', host='celery.com') # foreign, id 2 self.add_post(author_id=1, title='hi', body='hello sam') self.add_post(author_id=2, title='yo', body='sammy!') res = self.instance_feed(3) want = database_pb2.PostsEntry( global_id=1, author_id=1, title='hi', body='hello sam', creation_datetime={}, ) self.assertEqual(len(res.results), 1) self.assertIn(want, res.results)
def get_article_by_ap_id(self, obj_id): posts_req = database_pb2.PostsRequest( request_type=database_pb2.PostsRequest.FIND, match=database_pb2.PostsEntry(ap_id=obj_id, ), ) resp = self._db.Posts(posts_req) if resp.result_type != database_pb2.PostsResponse.OK: return None, resp.error elif len(resp.results) > 1: return None, "Recieved too many results from DB" elif len(resp.results) == 0: # NOTE: This can happen natually. # [email protected] follows [email protected]. # b.org sends a Like for an article by ross that already existed. # a.com didn't get the original Create so it can't find it. return None, "No matching DB entry for this article" return resp.results[0], None
def get_article(logger, db, global_id=None, ap_id=None): """ Retrieve a single PostEntry from the database. Returns None on error. """ logger.info("Getting article global_id: %s, ap_id: %s", global_id, ap_id) resp = db.Posts( database_pb2.PostsRequest(request_type=database_pb2.RequestType.FIND, match=database_pb2.PostsEntry( global_id=global_id, ap_id=ap_id, ))) if resp.result_type != general_pb2.ResultType.OK: logger.error("Error getting article: %s", resp.error) return None elif len(resp.results) == 0: logger.error("Could not find article") return None return resp.results[0]
def send_insert_request(self, req): global_id = req.author_id author = self._users_util.get_user_from_db(global_id=global_id) if author is None: self._logger.error( 'Could not find user id in db: ' + str(global_id)) return database_pb2.PostsResponse.error, None global_id = author.global_id html_body = md_to_html(self._md_stub, req.body) tags_string = convert_to_tags_string(req.tags) pe = database_pb2.PostsEntry( author_id=global_id, title=req.title, body=html_body, md_body=req.body, creation_datetime=req.creation_datetime, ap_id=req.ap_id, tags=tags_string, summary=req.summary, ) pr = database_pb2.PostsRequest( request_type=database_pb2.PostsRequest.INSERT, entry=pe ) posts_resp = self._db_stub.Posts(pr) if posts_resp.result_type == database_pb2.PostsResponse.ERROR: self._logger.error( 'Could not insert into db: %s', posts_resp.error) pe.global_id = posts_resp.global_id self.index(pe) # If post_recommender is on, send new post to post_recommender if self._post_recommendation_stub is not None: self._add_post_to_recommender(pe) return posts_resp.result_type, posts_resp.global_id
def __init__(self): self.posts_response = database_pb2.PostsResponse( result_type=general_pb2.ResultType.OK, results=[ database_pb2.PostsEntry( global_id=123, author_id=456, title="Minecraft Farming 101", body="Don't bother", ap_id="https://rabble.mojang.com/ap/@minecraft4ever/666", ) ]) self.users_response = database_pb2.UsersResponse( result_type=general_pb2.ResultType.OK, results=[ database_pb2.UsersEntry( global_id=456, handle="minecraft4ever", host="rabble.mojang.com", display_name="Minecraft4Ever", ) ], )
def __init__(self): self.posts_response = dbpb.PostsResponse( result_type=dbpb.PostsResponse.OK, results=[ dbpb.PostsEntry( global_id=3, author_id=123, title="Test", body="Test body", ap_id="https://rabble.cian.com/@cian/3", ), ], ) self.users_response = dbpb.UsersResponse( result_type=dbpb.UsersResponse.OK, results=[ dbpb.UsersEntry( global_id=123, handle="cian", host="rabble.cian.com", display_name="Cian", ), ], )
def test_equivalent_filter(self): entry = database_pb2.PostsEntry(title="Despacito") clause, vals = util.equivalent_filter(entry) self.assertEqual(clause, "title = ?") self.assertEqual(vals, ["Despacito"])