core/orm/author.py
Untone a40eb878be
Some checks failed
Deploy to core / deploy (push) Failing after 1m35s
async-events-fix
2024-02-21 14:21:04 +03:00

120 lines
4.4 KiB
Python

import time
import asyncio
from sqlalchemy import JSON, Boolean, Column, ForeignKey, Integer, String
from sqlalchemy import event, select
from services.rediscache import redis
from orm.topic import Topic, TopicFollower
from services.db import Base
class AuthorRating(Base):
__tablename__ = "author_rating"
id = None # type: ignore
rater = Column(ForeignKey("author.id"), primary_key=True)
author = Column(ForeignKey("author.id"), primary_key=True)
plus = Column(Boolean)
class AuthorFollower(Base):
__tablename__ = "author_follower"
id = None # type: ignore
follower = Column(ForeignKey("author.id"), primary_key=True)
author = Column(ForeignKey("author.id"), primary_key=True)
created_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
auto = Column(Boolean, nullable=False, default=False)
class Author(Base):
__tablename__ = "author"
user = Column(String) # unbounded link with authorizer's User type
name = Column(String, nullable=True, comment="Display name")
slug = Column(String, unique=True, comment="Author's slug")
bio = Column(String, nullable=True, comment="Bio") # status description
about = Column(String, nullable=True, comment="About") # long and formatted
pic = Column(String, nullable=True, comment="Picture")
links = Column(JSON, nullable=True, comment="Links")
created_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
last_seen = Column(Integer, nullable=False, default=lambda: int(time.time()))
updated_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
deleted_at = Column(Integer, nullable=True, comment="Deleted at")
@event.listens_for(Author, "after_insert")
@event.listens_for(Author, "after_update")
def after_author_update(mapper, connection, target):
redis_key = f"user:{target.user}:author"
asyncio.create_task(redis.execute("HSET", redis_key, **vars(target)))
async def update_follows_for_user(connection, user_id, entity_type, entity, is_insert):
redis_key = f"user:{user_id}:follows"
follows = await redis.execute("HGET", redis_key)
if not follows:
follows = {
"topics": [],
"authors": [],
"communities": [
{"slug": "discours", "name": "Дискурс", "id": 1, "desc": ""}
],
}
if is_insert:
follows[f"{entity_type}s"].append(entity)
else:
# Remove the entity from follows
follows[f"{entity_type}s"] = [
e for e in follows[f"{entity_type}s"] if e["id"] != entity.id
]
await redis.execute("HSET", redis_key, **vars(follows))
async def handle_author_follower_change(connection, author_id, follower_id, is_insert):
async with connection.begin() as conn:
author = await conn.execute(select(Author).filter(Author.id == author_id)).first()
follower = await conn.execute(select(Author).filter(Author.id == follower_id)).first()
if follower and author:
await update_follows_for_user(
connection, follower.user, "author", author, is_insert
)
async def handle_topic_follower_change(connection, topic_id, follower_id, is_insert):
topic = connection.execute(select(Topic).filter(Topic.id == topic_id)).first()
follower = connection.execute(
select(Author).filter(Author.id == follower_id)
).first()
if follower and topic:
await update_follows_for_user(
connection, follower.user, "topic", topic, is_insert
)
@event.listens_for(TopicFollower, "after_insert")
def after_topic_follower_insert(mapper, connection, target):
asyncio.create_task(handle_topic_follower_change(connection, target.topic, target.follower, True))
@event.listens_for(TopicFollower, "after_delete")
def after_topic_follower_delete(mapper, connection, target):
asyncio.create_task(handle_topic_follower_change(connection, target.topic, target.follower, False))
@event.listens_for(AuthorFollower, "after_insert")
def after_author_follower_insert(mapper, connection, target):
asyncio.create_task(handle_author_follower_change(
connection, target.author, target.follower, True
))
@event.listens_for(AuthorFollower, "after_delete")
def after_author_follower_delete(mapper, connection, target):
asyncio.create_task(handle_author_follower_change(
connection, target.author, target.follower, False
))