shoutscache, format

This commit is contained in:
tonyrewin 2022-09-07 19:19:06 +03:00
parent 742042398c
commit 365c2f25e7
9 changed files with 129 additions and 33 deletions

View File

@ -74,11 +74,8 @@ async def migrate(entry, storage):
reaction_dict["kind"] = ReactionKind.COMMENT reaction_dict["kind"] = ReactionKind.COMMENT
# creating reaction from old comment # creating reaction from old comment
day = (reaction_dict.get("createdAt") or ts).replace(
hour=0, minute=0, second=0, microsecond=0
)
reaction = Reaction.create(**reaction_dict) reaction = Reaction.create(**reaction_dict)
await ReactedStorage.increment(reaction) await ReactedStorage.react(reaction)
reaction_dict["id"] = reaction.id reaction_dict["id"] = reaction.id
for comment_rating_old in entry.get("ratings", []): for comment_rating_old in entry.get("ratings", []):
@ -106,7 +103,7 @@ async def migrate(entry, storage):
try: try:
# creating reaction from old rating # creating reaction from old rating
rr = Reaction.create(**re_reaction_dict) rr = Reaction.create(**re_reaction_dict)
await ReactedStorage.increment(rr) await ReactedStorage.react(rr)
except Exception as e: except Exception as e:
print("[migration] comment rating error: %r" % re_reaction_dict) print("[migration] comment rating error: %r" % re_reaction_dict)

View File

@ -269,11 +269,11 @@ async def migrate(entry, storage):
) )
reaction.update(reaction_dict) reaction.update(reaction_dict)
else: else:
reaction_dict['day'] = (reaction_dict.get("createdAt") or ts).replace( reaction_dict["day"] = (
hour=0, minute=0, second=0, microsecond=0 reaction_dict.get("createdAt") or ts
) ).replace(hour=0, minute=0, second=0, microsecond=0)
rea = Reaction.create(**reaction_dict) rea = Reaction.create(**reaction_dict)
await ReactedStorage.increment(rea) await ReactedStorage.react(rea)
# shout_dict['ratings'].append(reaction_dict) # shout_dict['ratings'].append(reaction_dict)
except Exception: except Exception:
raise Exception("[migration] content_item.ratings error: \n%r" % content_rating) raise Exception("[migration] content_item.ratings error: \n%r" % content_rating)

View File

@ -21,3 +21,4 @@ class Collection(Base):
pic = Column(String, nullable=True, comment="Picture") pic = Column(String, nullable=True, comment="Picture")
createdAt = Column(DateTime, default=datetime.now, comment="Created At") createdAt = Column(DateTime, default=datetime.now, comment="Created At")
createdBy = Column(ForeignKey("user.id"), comment="Created By") createdBy = Column(ForeignKey("user.id"), comment="Created By")
publishedAt = Column(DateTime, default=datetime.now, comment="Published At")

View File

@ -30,7 +30,6 @@ class Reaction(Base):
return { return {
"viewed": await ViewedStorage.get_reaction(self.id), "viewed": await ViewedStorage.get_reaction(self.id),
"reacted": len(await ReactedStorage.get_reaction(self.id)), "reacted": len(await ReactedStorage.get_reaction(self.id)),
# TODO: "replied"
"rating": await ReactedStorage.get_reaction_rating(self.id), "rating": await ReactedStorage.get_reaction_rating(self.id),
"commented": len(await ReactedStorage.get_reaction_comments(self.id)), "commented": len(await ReactedStorage.get_reaction_comments(self.id)),
} }

View File

@ -9,14 +9,14 @@ from sqlalchemy import and_
@mutation.field("createCollection") @mutation.field("createCollection")
@login_required @login_required
async def create_collection(_, info, input): async def create_collection(_, _info, inp):
# auth = info.context["request"].auth # auth = info.context["request"].auth
# user_id = auth.user_id # user_id = auth.user_id
collection = Collection.create( collection = Collection.create(
slug=input.get("slug", ""), slug=inp.get("slug", ""),
title=input.get("title", ""), title=inp.get("title", ""),
desc=input.get("desc", ""), desc=inp.get("desc", ""),
pic=input.get("pic", ""), pic=inp.get("pic", ""),
) )
return {"collection": collection} return {"collection": collection}
@ -24,7 +24,7 @@ async def create_collection(_, info, input):
@mutation.field("updateCollection") @mutation.field("updateCollection")
@login_required @login_required
async def update_collection(_, info, input): async def update_collection(_, info, inp):
auth = info.context["request"].auth auth = info.context["request"].auth
user_id = auth.user_id user_id = auth.user_id
collection_slug = input.get("slug", "") collection_slug = input.get("slug", "")
@ -38,9 +38,9 @@ async def update_collection(_, info, input):
return {"error": "invalid collection id"} return {"error": "invalid collection id"}
if collection.createdBy not in (owner + editors): if collection.createdBy not in (owner + editors):
return {"error": "access denied"} return {"error": "access denied"}
collection.title = input.get("title", "") collection.title = inp.get("title", "")
collection.desc = input.get("desc", "") collection.desc = inp.get("desc", "")
collection.pic = input.get("pic", "") collection.pic = inp.get("pic", "")
collection.updatedAt = datetime.now() collection.updatedAt = datetime.now()
session.commit() session.commit()
@ -63,7 +63,7 @@ async def delete_collection(_, info, slug):
@query.field("getUserCollections") @query.field("getUserCollections")
async def get_user_collections(_, info, userslug): async def get_user_collections(_, _info, userslug):
collections = [] collections = []
with local_session() as session: with local_session() as session:
user = session.query(User).filter(User.slug == userslug).first() user = session.query(User).filter(User.slug == userslug).first()

View File

@ -58,10 +58,10 @@ def reactions_unfollow(user, slug):
async def create_reaction(_, info, inp): async def create_reaction(_, info, inp):
user = info.context["request"].user user = info.context["request"].user
# TODO: filter allowed reaction kinds # TODO: filter allowed for post reaction kinds
reaction = Reaction.create(**inp) reaction = Reaction.create(**inp)
ReactedStorage.increment(reaction.shout, reaction.replyTo) ReactedStorage.react(reaction)
try: try:
reactions_follow(user, inp["shout"], True) reactions_follow(user, inp["shout"], True)
except Exception as e: except Exception as e:

View File

@ -18,42 +18,42 @@ from sqlalchemy.orm import selectinload
@query.field("topViewed") @query.field("topViewed")
async def top_viewed(_, info, page, size): async def top_viewed(_, info, page, size):
async with ShoutsCache.lock: async with ShoutsCache.lock:
return ShoutsCache.top_viewed[((page - 1) * size) : (page * size)] return ShoutsCache.get_top_viewed[((page - 1) * size) : (page * size)]
@query.field("topMonth") @query.field("topMonth")
async def top_month(_, info, page, size): async def top_month(_, info, page, size):
async with ShoutsCache.lock: async with ShoutsCache.lock:
return ShoutsCache.top_month[((page - 1) * size) : (page * size)] return ShoutsCache.get_top_month[((page - 1) * size) : (page * size)]
@query.field("topOverall") @query.field("topOverall")
async def top_overall(_, info, page, size): async def top_overall(_, info, page, size):
async with ShoutsCache.lock: async with ShoutsCache.lock:
return ShoutsCache.top_overall[((page - 1) * size) : (page * size)] return ShoutsCache.get_top_overall[((page - 1) * size) : (page * size)]
@query.field("recentPublished") @query.field("recentPublished")
async def recent_published(_, info, page, size): async def recent_published(_, info, page, size):
async with ShoutsCache.lock: async with ShoutsCache.lock:
return ShoutsCache.recent_published[((page - 1) * size) : (page * size)] return ShoutsCache.get_recent_published[((page - 1) * size) : (page * size)]
@query.field("recentAll") @query.field("recentAll")
async def recent_all(_, info, page, size): async def recent_all(_, info, page, size):
async with ShoutsCache.lock: async with ShoutsCache.lock:
return ShoutsCache.recent_all[((page - 1) * size) : (page * size)] return ShoutsCache.get_recent_all[((page - 1) * size) : (page * size)]
@query.field("recentReacted") @query.field("recentReacted")
async def recent_reacted(_, info, page, size): async def recent_reacted(_, info, page, size):
async with ShoutsCache.lock: async with ShoutsCache.lock:
return ShoutsCache.recent_reacted[((page - 1) * size) : (page * size)] return ShoutsCache.get_recent_reacted[((page - 1) * size) : (page * size)]
@mutation.field("viewShout") @mutation.field("viewShout")
async def view_shout(_, info, slug): async def view_shout(_, info, slug):
await ViewedStorage.inc_shout(slug) await ViewedStorage.increment(slug)
return {"error": ""} return {"error": ""}

View File

@ -4,7 +4,7 @@ from sqlalchemy import and_, desc, func, select
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from base.orm import local_session from base.orm import local_session
from orm.reaction import Reaction from orm.reaction import Reaction
from orm.shout import Shout from orm.shout import Shout, ShoutAuthor, ShoutTopic
from services.stat.reacted import ReactedStorage from services.stat.reacted import ReactedStorage
from services.stat.viewed import ViewedByDay from services.stat.viewed import ViewedByDay
@ -14,6 +14,16 @@ class ShoutsCache:
period = 60 * 60 # 1 hour period = 60 * 60 # 1 hour
lock = asyncio.Lock() lock = asyncio.Lock()
recent_published = []
recent_all = []
recent_reacted = []
top_month = []
top_overall = []
top_viewed = []
by_author = {}
by_topic = {}
@staticmethod @staticmethod
async def prepare_recent_published(): async def prepare_recent_published():
with local_session() as session: with local_session() as session:
@ -151,6 +161,82 @@ class ShoutsCache:
print("[zine.cache] %d top viewed shouts " % len(shouts)) print("[zine.cache] %d top viewed shouts " % len(shouts))
ShoutsCache.top_viewed = shouts ShoutsCache.top_viewed = shouts
@staticmethod
async def prepare_by_author():
shouts_by_author = {}
with local_session() as session:
for a in session.query(ShoutAuthor).all():
shout = session.query(Shout).filter(Shout.slug == a.shout).first()
if not shouts_by_author[a.author]:
shouts_by_author[a.author] = []
if shout not in shouts_by_author[a.author]:
shouts_by_author[a.author].push(shout)
async with ShoutsCache.lock:
print("[zine.cache indexed by %d authors " % len(shouts_by_author.keys()))
ShoutsCache.by_author = shouts_by_author
@staticmethod
async def prepare_by_topic():
shouts_by_topic = {}
with local_session() as session:
for t in session.query(ShoutTopic).all():
shout = session.query(Shout).filter(Shout.slug == t.shout).first()
if not shouts_by_topic[t.topic]:
shouts_by_topic[t.topic] = []
if shout not in shouts_by_topic[t.topic]:
shouts_by_topic[t.topic].push(shout)
async with ShoutsCache.lock:
print("[zine.cache] indexed by %d topics " % len(shouts_by_topic.keys()))
ShoutsCache.by_topic = shouts_by_topic
@staticmethod
async def get_shouts_by_author():
async with ShoutsCache.lock:
return ShoutsCache.by_author
@staticmethod
async def get_shouts_by_topic():
async with ShoutsCache.lock:
return ShoutsCache.by_topic
@staticmethod
async def get_top_overall():
async with ShoutsCache.lock:
return ShoutsCache.by_topic
@staticmethod
async def get_top_month():
async with ShoutsCache.lock:
return ShoutsCache.by_topic
@staticmethod
async def get_top_viewed():
async with ShoutsCache.lock:
return ShoutsCache.by_topic
@staticmethod
async def get_recent_published():
async with ShoutsCache.lock:
return ShoutsCache.recent_published
@staticmethod
async def get_recent_all():
async with ShoutsCache.lock:
return ShoutsCache.recent_all
@staticmethod
async def get_recent_reacted():
async with ShoutsCache.lock:
return ShoutsCache.recent_reacted
@staticmethod @staticmethod
async def worker(): async def worker():
while True: while True:
@ -158,9 +244,13 @@ class ShoutsCache:
await ShoutsCache.prepare_top_month() await ShoutsCache.prepare_top_month()
await ShoutsCache.prepare_top_overall() await ShoutsCache.prepare_top_overall()
await ShoutsCache.prepare_top_viewed() await ShoutsCache.prepare_top_viewed()
await ShoutsCache.prepare_recent_published() await ShoutsCache.prepare_recent_published()
await ShoutsCache.prepare_recent_all() await ShoutsCache.prepare_recent_all()
await ShoutsCache.prepare_recent_reacted() await ShoutsCache.prepare_recent_reacted()
await ShoutsCache.prepare_by_author()
await ShoutsCache.prepare_by_topic()
print("[zine.cache] periodical update") print("[zine.cache] periodical update")
except Exception as err: except Exception as err:
print("[zine.cache] error: %s" % (err)) print("[zine.cache] error: %s" % (err))

View File

@ -11,8 +11,8 @@ class TopicStorage:
self = TopicStorage self = TopicStorage
topics = session.query(Topic) topics = session.query(Topic)
self.topics = dict([(topic.slug, topic) for topic in topics]) self.topics = dict([(topic.slug, topic) for topic in topics])
for topic in self.topics.values(): for tpc in self.topics.values():
self.load_parents(topic) self.load_parents(tpc)
print("[zine.topics] %d precached" % len(self.topics.keys())) print("[zine.topics] %d precached" % len(self.topics.keys()))
@ -51,7 +51,16 @@ class TopicStorage:
return list(topics) return list(topics)
@staticmethod @staticmethod
async def add_topic(topic): async def get_topics_by_author(author):
self = TopicStorage
async with self.lock:
topics = filter(
lambda topic: topic.community == author, self.topics.values()
)
return list(topics)
@staticmethod
async def update_topic(topic):
self = TopicStorage self = TopicStorage
async with self.lock: async with self.lock:
self.topics[topic.slug] = topic self.topics[topic.slug] = topic