diff --git a/resolvers/author.py b/resolvers/author.py index 2c1332b6..9b64af41 100644 --- a/resolvers/author.py +++ b/resolvers/author.py @@ -17,6 +17,7 @@ from services.auth import login_required from services.db import local_session from services.schema import mutation, query from services.unread import get_total_unread_counter +from services.viewed import ViewedStorage logging.basicConfig() logger = logging.getLogger("\t[resolvers.author]\t") @@ -43,7 +44,7 @@ def add_author_stat_columns(q): return q -def get_authors_from_query(q): +async def get_authors_from_query(q): authors = [] with local_session() as session: for [author, shouts_stat, followers_stat, followings_stat] in session.execute(q): @@ -51,6 +52,7 @@ def get_authors_from_query(q): "shouts": shouts_stat, "followers": followers_stat, "followings": followings_stat, + "viewed": await ViewedStorage.get_author(author.slug), } authors.append(author) return authors @@ -154,10 +156,10 @@ def count_author_shouts_rating(session, author_id) -> int: -def load_author_with_stats(q): +async def load_author_with_stats(q): q = add_author_stat_columns(q) - result = get_authors_from_query(q) + result = await get_authors_from_query(q) if result: [author] = result @@ -199,7 +201,7 @@ async def get_author(_, _info, slug="", author_id=None): if author_id: q = select(Author).where(Author.id == author_id) - return load_author_with_stats(q) + return await load_author_with_stats(q) @query.field("get_author_id") @@ -207,7 +209,7 @@ async def get_author_id(_, _info, user: str): with local_session() as session: logger.info(f"[resolvers.author] getting author id for {user}") q = select(Author).filter(Author.user == user) - return load_author_with_stats(q) + return await load_author_with_stats(q) @query.field("load_authors_by") @@ -229,7 +231,7 @@ async def load_authors_by(_, _info, by, limit, offset): q = q.filter(Author.created_at > before) q = q.order_by(by.get("order", Author.created_at)).limit(limit).offset(offset) - return get_authors_from_query(q) + return await get_authors_from_query(q) @query.field("get_author_followed") @@ -261,7 +263,7 @@ async def get_author_followers(_, _info, slug) -> List[Author]: .where(aliased_author.slug == slug) ) - return get_authors_from_query(q) + return await get_authors_from_query(q) async def followed_authors(follower_id): @@ -269,7 +271,7 @@ async def followed_authors(follower_id): q = add_author_stat_columns(q) q = q.join(AuthorFollower, AuthorFollower.author == Author.id).where(AuthorFollower.follower == follower_id) # Pass the query to the get_authors_from_query function and return the results - return get_authors_from_query(q) + return await get_authors_from_query(q) @mutation.field("rate_author") diff --git a/resolvers/topic.py b/resolvers/topic.py index 3d46077c..277c6e60 100644 --- a/resolvers/topic.py +++ b/resolvers/topic.py @@ -7,6 +7,7 @@ from orm.topic import Topic, TopicFollower from services.auth import login_required from services.db import local_session from services.schema import mutation, query +from services.viewed import ViewedStorage async def followed_topics(follower_id): @@ -14,7 +15,7 @@ async def followed_topics(follower_id): q = add_topic_stat_columns(q) q = q.join(TopicFollower, TopicFollower.author == Author.id).where(TopicFollower.follower == follower_id) # Pass the query to the get_topics_from_query function and return the results - return get_topics_from_query(q) + return await get_topics_from_query(q) def add_topic_stat_columns(q): aliased_shout_author = aliased(ShoutAuthor) @@ -34,7 +35,7 @@ def add_topic_stat_columns(q): return q -def get_topics_from_query(q): +async def get_topics_from_query(q): topics = [] with local_session() as session: for [topic, shouts_stat, authors_stat, followers_stat] in session.execute(q): @@ -42,6 +43,7 @@ def get_topics_from_query(q): "shouts": shouts_stat, "authors": authors_stat, "followers": followers_stat, + "viewed": await ViewedStorage.get_topic(topic.slug), } topics.append(topic) @@ -53,15 +55,15 @@ async def get_topics_all(_, _info): q = select(Topic) q = add_topic_stat_columns(q) - return get_topics_from_query(q) + return await get_topics_from_query(q) -def topics_followed_by(author_id): +async def topics_followed_by(author_id): q = select(Topic, TopicFollower) q = add_topic_stat_columns(q) q = q.join(TopicFollower).where(TopicFollower.follower == author_id) - return get_topics_from_query(q) + return await get_topics_from_query(q) @query.field("get_topics_by_community") @@ -69,7 +71,7 @@ async def get_topics_by_community(_, _info, community_id: int): q = select(Topic).where(Topic.community == community_id) q = add_topic_stat_columns(q) - return get_topics_from_query(q) + return await get_topics_from_query(q) @query.field("get_topics_by_author") @@ -83,7 +85,7 @@ async def get_topics_by_author(_, _info, author_id=None, slug="", user=""): elif user: q = q.join(Author).where(Author.user == user) - return get_topics_from_query(q) + return await get_topics_from_query(q) @query.field("get_topic") @@ -91,7 +93,7 @@ async def get_topic(_, _info, slug): q = select(Topic).where(Topic.slug == slug) q = add_topic_stat_columns(q) - topics = get_topics_from_query(q) + topics = await get_topics_from_query(q) return topics[0] diff --git a/services/viewed.py b/services/viewed.py index a66ab232..26ca759f 100644 --- a/services/viewed.py +++ b/services/viewed.py @@ -82,9 +82,9 @@ def create_client(headers=None, schema=None): class ViewedStorage: lock = asyncio.Lock() - by_shouts = {} - by_topics = {} - by_authors = {} + views_by_shout = {} + shouts_by_topic = {} + shouts_by_author = {} views = None pages = None domains = None @@ -118,7 +118,7 @@ class ViewedStorage: try: with open("/dump/views.json", "r") as file: precounted_views = json.load(file) - self.by_shouts.update(precounted_views) + self.views_by_shout.update(precounted_views) logger.info(f" * {len(precounted_views)} pre-counted views loaded successfully.") except Exception as e: logger.error(f"Error loading pre-counted views: {e}") @@ -146,7 +146,7 @@ class ViewedStorage: slug = p.split("discours.io/")[-1] shouts[slug] = page["count"] for slug in shouts.keys(): - self.by_shouts[slug] = self.by_shouts.get(slug, 0) + 1 + self.views_by_shout[slug] = self.views_by_shout.get(slug, 0) + 1 self.update_topics(slug) logger.info(" ⎪ %d pages collected " % len(shouts.keys())) @@ -175,14 +175,14 @@ class ViewedStorage: """getting shout views metric by slug""" self = ViewedStorage async with self.lock: - return self.by_shouts.get(shout_slug, 0) + return self.views_by_shout.get(shout_slug, 0) @staticmethod async def get_shout_media(shout_slug) -> Dict[str, int]: """getting shout plays metric by slug""" self = ViewedStorage async with self.lock: - return self.by_shouts.get(shout_slug, 0) + return self.views_by_shout.get(shout_slug, 0) @staticmethod async def get_topic(topic_slug) -> int: @@ -190,40 +190,35 @@ class ViewedStorage: self = ViewedStorage topic_views = 0 async with self.lock: - for shout_slug in self.by_topics.get(topic_slug, {}).keys(): - topic_views += self.by_topics[topic_slug].get(shout_slug, 0) + for shout_slug in self.shouts_by_topic.get(topic_slug, []): + topic_views += self.views_by_shout.get(shout_slug, 0) return topic_views @staticmethod - async def get_authors(author_slug) -> int: + async def get_author(author_slug) -> int: """getting author views value summed""" self = ViewedStorage author_views = 0 async with self.lock: - for shout_slug in self.by_authors.get(author_slug, {}).keys(): - author_views += self.by_authors[author_slug].get(shout_slug, 0) + for shout_slug in self.shouts_by_author.get(author_slug, []): + author_views += self.views_by_shout.get(shout_slug, 0) return author_views @staticmethod def update_topics(shout_slug): - """updates topics counters by shout slug""" + """Updates topics counters by shout slug""" self = ViewedStorage with local_session() as session: - # grouped by topics - for [_shout_topic, topic] in ( - session.query(ShoutTopic, Topic).join(Topic).join(Shout).where(Shout.slug == shout_slug).all() - ): - if not self.by_topics.get(topic.slug): - self.by_topics[topic.slug] = {} - self.by_topics[topic.slug][shout_slug] = self.by_shouts[shout_slug] + # Define a helper function to avoid code repetition + def update_groups(dictionary, key, value): + dictionary[key] = list(set(dictionary.get(key, []) + [value])) - # grouped by authors - for [_shout_author, author] in ( - session.query(ShoutAuthor, Author).join(Author).join(Shout).where(Shout.slug == shout_slug).all() - ): - if not self.by_authors.get(author.slug): - self.by_authors[author.slug] = {} - self.by_authors[author.slug][shout_slug] = self.by_shouts[shout_slug] + # Update topics and authors using the helper function + for [_shout_topic, topic] in session.query(ShoutTopic, Topic).join(Topic).join(Shout).where(Shout.slug == shout_slug).all(): + update_groups(self.shouts_by_topic, topic.slug, shout_slug) + + for [_shout_topic, author] in session.query(ShoutAuthor, Author).join(Author).join(Shout).where(Shout.slug == shout_slug).all(): + update_groups(self.shouts_by_author, author.slug, shout_slug) @staticmethod async def increment(shout_slug): @@ -231,7 +226,7 @@ class ViewedStorage: resource = ackee_site + shout_slug self = ViewedStorage async with self.lock: - self.by_shouts[shout_slug] = self.by_shouts.get(shout_slug, 0) + 1 + self.views_by_shout[shout_slug] = self.views_by_shout.get(shout_slug, 0) + 1 self.update_topics(shout_slug) variables = {"domainId": domain_id, "input": {"siteLocation": resource}} if self.client: