core/resolvers/zine.py

381 lines
12 KiB
Python
Raw Normal View History

2022-06-21 12:21:02 +00:00
from orm import Shout, ShoutAuthor, ShoutTopic, ShoutRating, ShoutViewByDay, \
User, Community, Resource, ShoutRatingStorage, ShoutViewStorage, \
Comment, CommentRating, Topic, ShoutCommentsSubscription
2022-06-12 08:33:24 +00:00
from orm.community import CommunitySubscription
2021-08-07 16:14:20 +00:00
from orm.base import local_session
from orm.user import UserStorage, AuthorSubscription
from orm.topic import TopicSubscription
2021-07-27 04:58:06 +00:00
2021-08-07 16:14:20 +00:00
from resolvers.base import mutation, query
2022-06-29 10:47:53 +00:00
from resolvers.profile import author_subscribe, author_unsubscribe
from resolvers.topics import topic_subscribe, topic_unsubscribe
from resolvers.community import community_subscribe, community_unsubscribe
2022-06-21 12:21:02 +00:00
from resolvers.comments import comments_subscribe, comments_unsubscribe
2021-08-07 16:14:20 +00:00
from auth.authenticate import login_required
from settings import SHOUTS_REPO
import subprocess
2021-08-08 09:49:15 +00:00
import asyncio
2021-08-31 15:15:27 +00:00
from datetime import datetime, timedelta
2021-08-08 09:49:15 +00:00
2021-08-08 12:23:12 +00:00
from pathlib import Path
2021-09-25 11:40:37 +00:00
from sqlalchemy import select, func, desc, and_
2021-09-24 14:39:37 +00:00
from sqlalchemy.orm import selectinload
2021-08-08 12:23:12 +00:00
2021-08-08 09:49:15 +00:00
class GitTask:
queue = asyncio.Queue()
2021-08-28 10:13:50 +00:00
def __init__(self, input, username, user_email, comment):
2021-10-31 08:50:49 +00:00
self.slug = input["slug"]
self.shout_body = input["body"]
self.username = username
self.user_email = user_email
self.comment = comment
2021-08-08 09:49:15 +00:00
GitTask.queue.put_nowait(self)
2021-08-08 12:23:12 +00:00
def init_repo(self):
2021-08-28 10:13:50 +00:00
repo_path = "%s" % (SHOUTS_REPO)
2021-08-08 12:23:12 +00:00
Path(repo_path).mkdir()
2021-12-17 16:14:08 +00:00
cmd = "cd %s && git init && " \
"git config user.name 'discours' && " \
"git config user.email 'discours@discours.io' && " \
"touch initial && git add initial && " \
"git commit -m 'init repo'" \
% (repo_path)
2021-08-08 12:23:12 +00:00
output = subprocess.check_output(cmd, shell=True)
print(output)
2021-08-08 09:49:15 +00:00
def execute(self):
2021-08-28 10:13:50 +00:00
repo_path = "%s" % (SHOUTS_REPO)
2021-08-08 12:23:12 +00:00
if not Path(repo_path).exists():
self.init_repo()
2021-12-17 16:14:08 +00:00
#cmd = "cd %s && git checkout master" % (repo_path)
#output = subprocess.check_output(cmd, shell=True)
#print(output)
2021-08-08 09:49:15 +00:00
2022-06-25 19:14:16 +00:00
shout_filename = "%s.mdx" % (self.slug)
2021-08-08 12:23:12 +00:00
shout_full_filename = "%s/%s" % (repo_path, shout_filename)
2021-08-08 09:49:15 +00:00
with open(shout_full_filename, mode='w', encoding='utf-8') as shout_file:
shout_file.write(self.shout_body)
author = "%s <%s>" % (self.username, self.user_email)
2021-08-08 12:23:12 +00:00
cmd = "cd %s && git add %s && git commit -m '%s' --author='%s'" % \
(repo_path, shout_filename, self.comment, author)
2021-08-08 09:49:15 +00:00
output = subprocess.check_output(cmd, shell=True)
print(output)
@staticmethod
async def git_task_worker():
print("git task worker start")
while True:
task = await GitTask.queue.get()
try:
task.execute()
except Exception as err:
print("git task worker error = %s" % (err))
2021-07-27 04:58:06 +00:00
2021-10-31 17:55:59 +00:00
class ShoutsCache:
2022-01-08 09:11:12 +00:00
limit = 200
2021-09-01 10:28:42 +00:00
period = 60*60 #1 hour
lock = asyncio.Lock()
2021-10-30 16:58:15 +00:00
@staticmethod
2022-06-12 06:10:00 +00:00
async def prepare_recent_published():
2021-10-30 18:54:50 +00:00
with local_session() as session:
2021-10-31 09:55:25 +00:00
stmt = select(Shout).\
2021-11-04 12:06:49 +00:00
options(selectinload(Shout.authors), selectinload(Shout.topics)).\
2021-11-15 08:43:38 +00:00
where(Shout.publishedAt != None).\
2021-12-17 14:56:05 +00:00
order_by(desc("publishedAt")).\
2021-10-31 17:55:59 +00:00
limit(ShoutsCache.limit)
2021-10-30 18:54:50 +00:00
shouts = []
for row in session.execute(stmt):
shout = row.Shout
shout.ratings = await ShoutRatingStorage.get_ratings(shout.slug)
2021-10-30 18:54:50 +00:00
shouts.append(shout)
2021-10-31 17:55:59 +00:00
async with ShoutsCache.lock:
2022-06-12 06:10:00 +00:00
ShoutsCache.recent_published = shouts
2021-10-30 18:54:50 +00:00
2022-06-11 22:05:20 +00:00
@staticmethod
async def prepare_recent_all():
with local_session() as session:
stmt = select(Shout).\
options(selectinload(Shout.authors), selectinload(Shout.topics)).\
2022-06-12 06:10:00 +00:00
order_by(desc("createdAt")).\
2022-06-11 22:05:20 +00:00
limit(ShoutsCache.limit)
shouts = []
for row in session.execute(stmt):
shout = row.Shout
shout.ratings = await ShoutRatingStorage.get_ratings(shout.slug)
shouts.append(shout)
async with ShoutsCache.lock:
ShoutsCache.recent_all = shouts
2022-02-03 09:13:53 +00:00
@staticmethod
async def prepare_recent_commented():
with local_session() as session:
2022-02-15 11:12:54 +00:00
stmt = select(Shout, func.max(Comment.createdAt).label("commentCreatedAt")).\
2022-02-03 09:13:53 +00:00
options(selectinload(Shout.authors), selectinload(Shout.topics)).\
join(Comment).\
2022-02-15 11:12:54 +00:00
where(and_(Shout.publishedAt != None, Comment.deletedAt == None)).\
group_by(Shout.slug).\
order_by(desc("commentCreatedAt")).\
2022-02-03 09:13:53 +00:00
limit(ShoutsCache.limit)
shouts = []
for row in session.execute(stmt):
shout = row.Shout
shout.ratings = await ShoutRatingStorage.get_ratings(shout.slug)
shouts.append(shout)
async with ShoutsCache.lock:
2022-02-15 11:12:54 +00:00
ShoutsCache.recent_commented = shouts
2022-02-03 09:13:53 +00:00
2021-10-30 16:58:15 +00:00
2021-09-01 16:03:00 +00:00
@staticmethod
2021-10-31 14:50:55 +00:00
async def prepare_top_overall():
with local_session() as session:
stmt = select(Shout, func.sum(ShoutRating.value).label("rating")).\
2021-11-04 12:06:49 +00:00
options(selectinload(Shout.authors), selectinload(Shout.topics)).\
2021-10-31 14:50:55 +00:00
join(ShoutRating).\
2021-11-15 08:43:38 +00:00
where(Shout.publishedAt != None).\
2021-12-13 07:50:33 +00:00
group_by(Shout.slug).\
2021-10-31 14:50:55 +00:00
order_by(desc("rating")).\
2021-10-31 17:55:59 +00:00
limit(ShoutsCache.limit)
2021-10-31 14:50:55 +00:00
shouts = []
for row in session.execute(stmt):
shout = row.Shout
shout.ratings = await ShoutRatingStorage.get_ratings(shout.slug)
2021-10-31 14:50:55 +00:00
shouts.append(shout)
2021-10-31 17:55:59 +00:00
async with ShoutsCache.lock:
ShoutsCache.top_overall = shouts
2021-10-31 14:50:55 +00:00
@staticmethod
async def prepare_top_month():
2021-11-04 11:26:50 +00:00
month_ago = datetime.now() - timedelta(days = 30)
2021-09-01 16:03:00 +00:00
with local_session() as session:
stmt = select(Shout, func.sum(ShoutRating.value).label("rating")).\
2021-11-04 12:06:49 +00:00
options(selectinload(Shout.authors), selectinload(Shout.topics)).\
2021-09-01 16:03:00 +00:00
join(ShoutRating).\
2021-11-15 08:43:38 +00:00
where(and_(Shout.createdAt > month_ago, Shout.publishedAt != None)).\
2021-12-13 07:50:33 +00:00
group_by(Shout.slug).\
2021-09-01 16:03:00 +00:00
order_by(desc("rating")).\
2021-10-31 17:55:59 +00:00
limit(ShoutsCache.limit)
2021-09-01 16:03:00 +00:00
shouts = []
for row in session.execute(stmt):
shout = row.Shout
shout.ratings = await ShoutRatingStorage.get_ratings(shout.slug)
2021-09-01 16:03:00 +00:00
shouts.append(shout)
2021-10-31 17:55:59 +00:00
async with ShoutsCache.lock:
ShoutsCache.top_month = shouts
2021-09-01 16:03:00 +00:00
2021-09-01 10:28:42 +00:00
@staticmethod
2021-10-31 15:09:16 +00:00
async def prepare_top_viewed():
2021-11-04 11:26:50 +00:00
month_ago = datetime.now() - timedelta(days = 30)
2021-09-01 10:28:42 +00:00
with local_session() as session:
2021-11-04 11:26:50 +00:00
stmt = select(Shout, func.sum(ShoutViewByDay.value).label("views")).\
2021-11-04 12:06:49 +00:00
options(selectinload(Shout.authors), selectinload(Shout.topics)).\
2021-09-01 10:28:42 +00:00
join(ShoutViewByDay).\
2021-11-15 08:43:38 +00:00
where(and_(ShoutViewByDay.day > month_ago, Shout.publishedAt != None)).\
2021-12-13 07:50:33 +00:00
group_by(Shout.slug).\
2021-11-04 11:26:50 +00:00
order_by(desc("views")).\
2021-10-31 17:55:59 +00:00
limit(ShoutsCache.limit)
2021-09-01 10:28:42 +00:00
shouts = []
for row in session.execute(stmt):
shout = row.Shout
shout.ratings = await ShoutRatingStorage.get_ratings(shout.slug)
2021-11-04 11:26:50 +00:00
shout.views = row.views
2021-09-01 10:28:42 +00:00
shouts.append(shout)
2021-10-31 17:55:59 +00:00
async with ShoutsCache.lock:
ShoutsCache.top_viewed = shouts
2021-09-01 16:03:00 +00:00
2021-09-01 10:28:42 +00:00
@staticmethod
async def worker():
2021-10-30 20:56:49 +00:00
print("shouts cache worker start")
2021-09-01 10:28:42 +00:00
while True:
try:
2021-10-30 20:56:49 +00:00
print("shouts cache updating...")
2021-10-31 17:55:59 +00:00
await ShoutsCache.prepare_top_month()
await ShoutsCache.prepare_top_overall()
await ShoutsCache.prepare_top_viewed()
2022-06-12 06:10:00 +00:00
await ShoutsCache.prepare_recent_published()
2022-06-11 22:05:20 +00:00
await ShoutsCache.prepare_recent_all()
2022-02-03 09:13:53 +00:00
await ShoutsCache.prepare_recent_commented()
2021-10-30 20:56:49 +00:00
print("shouts cache update finished")
2021-09-01 10:28:42 +00:00
except Exception as err:
2021-10-30 20:56:49 +00:00
print("shouts cache worker error = %s" % (err))
2021-10-31 17:55:59 +00:00
await asyncio.sleep(ShoutsCache.period)
2021-09-01 10:28:42 +00:00
2021-10-31 15:09:16 +00:00
@query.field("topViewed")
2021-12-17 18:14:31 +00:00
async def top_viewed(_, info, page, size):
2021-10-31 17:55:59 +00:00
async with ShoutsCache.lock:
2022-01-08 09:09:06 +00:00
return ShoutsCache.top_viewed[(page - 1) * size : page * size]
2021-07-27 05:41:45 +00:00
2021-10-31 14:50:55 +00:00
@query.field("topMonth")
2021-12-17 18:14:31 +00:00
async def top_month(_, info, page, size):
2021-10-31 17:55:59 +00:00
async with ShoutsCache.lock:
2022-01-08 09:09:06 +00:00
return ShoutsCache.top_month[(page - 1) * size : page * size]
2021-10-31 14:50:55 +00:00
@query.field("topOverall")
2021-12-17 18:14:31 +00:00
async def top_overall(_, info, page, size):
2021-10-31 17:55:59 +00:00
async with ShoutsCache.lock:
2022-01-08 09:09:06 +00:00
return ShoutsCache.top_overall[(page - 1) * size : page * size]
2021-10-30 19:15:29 +00:00
2022-06-11 22:05:20 +00:00
@query.field("recentPublished")
2022-06-12 06:10:00 +00:00
async def recent_published(_, info, page, size):
2021-10-31 17:55:59 +00:00
async with ShoutsCache.lock:
2022-06-12 06:10:00 +00:00
return ShoutsCache.recent_published[(page - 1) * size : page * size]
2021-09-01 16:03:00 +00:00
2022-06-11 22:05:20 +00:00
@query.field("recentAll")
async def recent_all(_, info, page, size):
async with ShoutsCache.lock:
return ShoutsCache.recent_all[(page - 1) * size : page * size]
2022-02-03 09:13:53 +00:00
@query.field("recentCommented")
2022-06-11 22:05:20 +00:00
async def recent_commented(_, info, page, size):
2022-02-03 09:13:53 +00:00
async with ShoutsCache.lock:
return ShoutsCache.recent_commented[(page - 1) * size : page * size]
2021-09-27 14:59:44 +00:00
@mutation.field("viewShout")
2021-12-13 07:50:33 +00:00
async def view_shout(_, info, slug):
await ShoutViewStorage.inc_view(slug)
2021-09-27 14:59:44 +00:00
return {"error" : ""}
2021-09-24 14:39:37 +00:00
@query.field("getShoutBySlug")
2021-09-05 07:16:28 +00:00
async def get_shout_by_slug(_, info, slug):
all_fields = [node.name.value for node in info.field_nodes[0].selection_set.selections]
2021-12-12 10:54:06 +00:00
selected_fields = set(["authors", "topics"]).intersection(all_fields)
select_options = [selectinload(getattr(Shout, field)) for field in selected_fields]
2021-09-25 11:40:37 +00:00
2021-09-03 07:16:19 +00:00
with local_session() as session:
2021-09-24 14:39:37 +00:00
shout = session.query(Shout).\
2021-09-25 11:40:37 +00:00
options(select_options).\
2021-09-24 14:39:37 +00:00
filter(Shout.slug == slug).first()
if not shout:
2022-06-15 07:05:20 +00:00
print(f"shout with slug {slug} not exist")
return {} #TODO return error field
shout.ratings = await ShoutRatingStorage.get_ratings(slug)
2021-09-05 08:56:15 +00:00
return shout
2021-12-06 14:50:49 +00:00
@query.field("getShoutComments")
2021-12-13 07:50:33 +00:00
async def get_shout_comments(_, info, slug):
2021-12-06 14:50:49 +00:00
with local_session() as session:
2021-12-12 10:54:06 +00:00
comments = session.query(Comment).\
options(selectinload(Comment.ratings)).\
2021-12-13 07:50:33 +00:00
filter(Comment.shout == slug).\
2021-12-06 14:50:49 +00:00
group_by(Comment.id).all()
2021-12-12 10:54:06 +00:00
for comment in comments:
2021-12-06 14:50:49 +00:00
comment.author = await UserStorage.get_user(comment.author)
return comments
2022-05-31 07:03:50 +00:00
@query.field("shoutsByTopics")
async def shouts_by_topics(_, info, slugs, page, size):
2022-01-08 09:09:06 +00:00
page = page - 1
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutTopic).\
2022-05-31 07:03:50 +00:00
where(and_(ShoutTopic.topic.in_(slugs), Shout.publishedAt != None)).\
2021-12-17 14:56:05 +00:00
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset(page * size)
return shouts
2022-05-31 07:03:50 +00:00
@query.field("shoutsByAuthors")
async def shouts_by_authors(_, info, slugs, page, size):
2022-01-08 09:09:06 +00:00
page = page - 1
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutAuthor).\
2022-05-31 07:03:50 +00:00
where(and_(ShoutAuthor.user.in_(slugs), Shout.publishedAt != None)).\
2021-12-17 14:56:05 +00:00
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset(page * size)
return shouts
2022-05-31 07:03:50 +00:00
@query.field("shoutsByCommunities")
async def shouts_by_communities(_, info, slugs, page, size):
2022-01-08 09:09:06 +00:00
page = page - 1
with local_session() as session:
2021-12-17 14:27:16 +00:00
#TODO fix postgres high load
shouts = session.query(Shout).distinct().\
join(ShoutTopic).\
2021-12-17 14:56:05 +00:00
where(and_(Shout.publishedAt != None,\
ShoutTopic.topic.in_(\
2022-05-31 07:03:50 +00:00
select(Topic.slug).where(Topic.community.in_(slugs))\
2021-12-17 14:56:05 +00:00
))).\
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset(page * size)
return shouts
2022-01-30 11:28:27 +00:00
2022-06-19 17:54:39 +00:00
@mutation.field("subscribe")
@login_required
2022-06-29 10:47:53 +00:00
async def subscribe(_, info, what, slug):
user = info.context["request"].user
2022-06-19 17:54:39 +00:00
try:
2022-06-29 10:47:53 +00:00
if what == "AUTHOR":
2022-06-19 17:54:39 +00:00
author_subscribe(user, slug)
2022-06-29 10:47:53 +00:00
elif what == "TOPIC":
2022-06-19 17:54:39 +00:00
topic_subscribe(user, slug)
2022-06-29 10:47:53 +00:00
elif what == "COMMUNITY":
2022-06-19 17:54:39 +00:00
community_subscribe(user, slug)
2022-06-29 10:47:53 +00:00
elif what == "COMMENTS":
2022-06-21 12:21:02 +00:00
comments_subscribe(user, slug)
2022-06-19 17:54:39 +00:00
except Exception as e:
2022-06-29 12:22:14 +00:00
return {"error" : str(e)}
2022-06-19 17:54:39 +00:00
return {}
2022-06-19 17:54:39 +00:00
@mutation.field("unsubscribe")
@login_required
2022-06-29 10:47:53 +00:00
async def unsubscribe(_, info, what, slug):
user = info.context["request"].user
2022-01-30 11:28:27 +00:00
2022-06-19 17:54:39 +00:00
try:
2022-06-29 10:47:53 +00:00
if what == "AUTHOR":
2022-06-19 17:54:39 +00:00
author_unsubscribe(user, slug)
2022-06-29 10:47:53 +00:00
elif what == "TOPIC":
2022-06-19 17:54:39 +00:00
topic_unsubscribe(user, slug)
2022-06-29 10:47:53 +00:00
elif what == "COMMUNITY":
2022-06-19 17:54:39 +00:00
community_unsubscribe(user, slug)
2022-06-29 10:47:53 +00:00
elif what == "COMMENTS":
2022-06-21 12:21:02 +00:00
comments_unsubscribe(user, slug)
2022-06-19 17:54:39 +00:00
except Exception as e:
2022-06-29 12:22:14 +00:00
return {"error" : str(e)}
2022-01-31 09:16:46 +00:00
2022-06-19 17:54:39 +00:00
return {}
2022-04-28 09:04:14 +00:00
2022-04-28 09:36:48 +00:00
2022-06-19 17:54:39 +00:00
@mutation.field("rateShout")
2022-04-29 08:01:04 +00:00
@login_required
2022-06-19 17:54:39 +00:00
async def rate_shout(_, info, slug, value):
auth = info.context["request"].auth
2022-04-29 08:01:04 +00:00
user = info.context["request"].user
2022-04-28 09:36:48 +00:00
with local_session() as session:
2022-06-19 17:54:39 +00:00
rating = session.query(ShoutRating).\
filter(and_(ShoutRating.rater == user.slug, ShoutRating.shout == slug)).first()
if rating:
rating.value = value;
rating.ts = datetime.now()
session.commit()
else:
rating = ShoutRating.create(
rater = user.slug,
shout = slug,
value = value
)
2022-04-29 08:27:34 +00:00
2022-06-19 17:54:39 +00:00
await ShoutRatingStorage.update_rating(rating)
2022-04-29 08:27:34 +00:00
2022-06-29 10:47:53 +00:00
return {"error" : ""}