2021-09-24 14:39:37 +00:00
|
|
|
from orm import Shout, ShoutAuthor, ShoutTopic, ShoutRating, ShoutViewByDay, User, Community, Resource,\
|
2021-09-29 12:59:48 +00:00
|
|
|
rating_storage, ShoutViewStorage
|
2021-08-07 16:14:20 +00:00
|
|
|
from orm.base import local_session
|
2021-07-27 04:58:06 +00:00
|
|
|
|
2021-08-07 16:14:20 +00:00
|
|
|
from resolvers.base import mutation, query
|
|
|
|
|
|
|
|
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-08-08 12:23:12 +00:00
|
|
|
self.slug = input["slug"];
|
|
|
|
self.shout_body = input["body"];
|
2021-08-08 09:49:15 +00:00
|
|
|
self.username = username;
|
|
|
|
self.user_email = user_email;
|
|
|
|
self.comment = comment;
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
cmd = "cd %s && git init && touch initial && git add initial && git commit -m 'init repo'" % (repo_path)
|
|
|
|
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()
|
|
|
|
|
|
|
|
cmd = "cd %s && git checkout master" % (repo_path)
|
2021-08-08 09:49:15 +00:00
|
|
|
output = subprocess.check_output(cmd, shell=True)
|
|
|
|
print(output)
|
|
|
|
|
2021-08-08 12:23:12 +00:00
|
|
|
shout_filename = "%s.md" % (self.slug)
|
|
|
|
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-09-01 10:28:42 +00:00
|
|
|
class TopShouts:
|
|
|
|
limit = 50
|
|
|
|
period = 60*60 #1 hour
|
|
|
|
|
|
|
|
lock = asyncio.Lock()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
async def prepare_shouts_by_rating():
|
|
|
|
month_ago = datetime.now() - timedelta(days = 30)
|
|
|
|
with local_session() as session:
|
|
|
|
stmt = select(Shout, func.sum(ShoutRating.value).label("rating")).\
|
|
|
|
join(ShoutRating).\
|
|
|
|
where(ShoutRating.ts > month_ago).\
|
|
|
|
group_by(Shout.id).\
|
|
|
|
order_by(desc("rating")).\
|
|
|
|
limit(TopShouts.limit)
|
|
|
|
shouts = []
|
|
|
|
for row in session.execute(stmt):
|
|
|
|
shout = row.Shout
|
|
|
|
shout.rating = row.rating
|
|
|
|
shouts.append(shout)
|
|
|
|
async with TopShouts.lock:
|
|
|
|
TopShouts.shouts_by_rating = shouts
|
|
|
|
|
2021-09-01 16:03:00 +00:00
|
|
|
@staticmethod
|
|
|
|
async def prepare_favorites_shouts():
|
|
|
|
with local_session() as session:
|
|
|
|
stmt = select(Shout, func.sum(ShoutRating.value).label("rating")).\
|
|
|
|
join(ShoutRating).\
|
|
|
|
group_by(Shout.id).\
|
|
|
|
order_by(desc("rating")).\
|
|
|
|
limit(TopShouts.limit)
|
|
|
|
shouts = []
|
|
|
|
for row in session.execute(stmt):
|
|
|
|
shout = row.Shout
|
|
|
|
shout.rating = row.rating
|
|
|
|
shouts.append(shout)
|
|
|
|
async with TopShouts.lock:
|
|
|
|
TopShouts.favorites_shouts = shouts
|
|
|
|
|
2021-09-01 10:28:42 +00:00
|
|
|
@staticmethod
|
|
|
|
async def prepare_shouts_by_view():
|
|
|
|
month_ago = datetime.now() - timedelta(days = 30)
|
|
|
|
with local_session() as session:
|
|
|
|
stmt = select(Shout, func.sum(ShoutViewByDay.value).label("view")).\
|
|
|
|
join(ShoutViewByDay).\
|
|
|
|
where(ShoutViewByDay.day > month_ago).\
|
|
|
|
group_by(Shout.id).\
|
|
|
|
order_by(desc("view")).\
|
|
|
|
limit(TopShouts.limit)
|
|
|
|
shouts = []
|
|
|
|
for row in session.execute(stmt):
|
|
|
|
shout = row.Shout
|
|
|
|
shout.view = row.view
|
|
|
|
shouts.append(shout)
|
|
|
|
async with TopShouts.lock:
|
|
|
|
TopShouts.shouts_by_view = shouts
|
|
|
|
|
2021-09-01 16:03:00 +00:00
|
|
|
@staticmethod
|
2021-09-02 11:04:58 +00:00
|
|
|
async def prepare_top_authors():
|
2021-09-01 16:03:00 +00:00
|
|
|
month_ago = datetime.now() - timedelta(days = 30)
|
|
|
|
with local_session() as session:
|
|
|
|
shout_with_view = select(Shout.id, func.sum(ShoutViewByDay.value).label("view")).\
|
|
|
|
join(ShoutViewByDay).\
|
|
|
|
where(ShoutViewByDay.day > month_ago).\
|
|
|
|
group_by(Shout.id).\
|
|
|
|
order_by(desc("view")).cte()
|
2021-09-02 11:04:58 +00:00
|
|
|
stmt = select(ShoutAuthor.user, func.sum(shout_with_view.c.view).label("view")).\
|
|
|
|
join(shout_with_view, ShoutAuthor.shout == shout_with_view.c.id).\
|
|
|
|
group_by(ShoutAuthor.user).\
|
|
|
|
order_by(desc("view")).\
|
|
|
|
limit(TopShouts.limit)
|
|
|
|
authors = {}
|
2021-09-01 16:03:00 +00:00
|
|
|
for row in session.execute(stmt):
|
2021-09-02 11:04:58 +00:00
|
|
|
authors[row.user] = row.view
|
|
|
|
authors_ids = authors.keys()
|
|
|
|
authors = session.query(User).filter(User.id.in_(authors_ids)).all()
|
2021-09-01 16:03:00 +00:00
|
|
|
async with TopShouts.lock:
|
2021-09-02 11:04:58 +00:00
|
|
|
TopShouts.top_authors = authors
|
2021-09-01 16:03:00 +00:00
|
|
|
|
|
|
|
|
2021-09-01 10:28:42 +00:00
|
|
|
@staticmethod
|
|
|
|
async def worker():
|
|
|
|
print("top shouts worker start")
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
print("top shouts: update cache")
|
2021-09-01 16:03:00 +00:00
|
|
|
await TopShouts.prepare_favorites_shouts()
|
2021-09-01 10:28:42 +00:00
|
|
|
await TopShouts.prepare_shouts_by_rating()
|
|
|
|
await TopShouts.prepare_shouts_by_view()
|
2021-09-02 11:04:58 +00:00
|
|
|
await TopShouts.prepare_top_authors()
|
2021-09-01 10:28:42 +00:00
|
|
|
print("top shouts: update finished")
|
|
|
|
except Exception as err:
|
|
|
|
print("top shouts worker error = %s" % (err))
|
|
|
|
await asyncio.sleep(TopShouts.period)
|
|
|
|
|
|
|
|
|
2021-08-30 07:41:59 +00:00
|
|
|
@query.field("topShoutsByView")
|
|
|
|
async def top_shouts_by_view(_, info, limit):
|
2021-09-01 10:28:42 +00:00
|
|
|
async with TopShouts.lock:
|
|
|
|
return TopShouts.shouts_by_view[:limit]
|
2021-07-27 05:41:45 +00:00
|
|
|
|
|
|
|
|
2021-08-30 07:41:59 +00:00
|
|
|
@query.field("topShoutsByRating")
|
2021-09-01 16:03:00 +00:00
|
|
|
async def top_shouts_by_rating(_, info, limit):
|
2021-09-01 10:28:42 +00:00
|
|
|
async with TopShouts.lock:
|
|
|
|
return TopShouts.shouts_by_rating[:limit]
|
2021-07-27 05:41:45 +00:00
|
|
|
|
|
|
|
|
2021-09-01 16:03:00 +00:00
|
|
|
@query.field("favoritesShouts")
|
|
|
|
async def favorites_shouts(_, info, limit):
|
|
|
|
async with TopShouts.lock:
|
|
|
|
return TopShouts.favorites_shouts[:limit]
|
|
|
|
|
|
|
|
|
2021-09-02 11:04:58 +00:00
|
|
|
@query.field("topAuthors")
|
|
|
|
async def top_authors(_, info, limit):
|
2021-09-01 16:03:00 +00:00
|
|
|
async with TopShouts.lock:
|
2021-09-02 11:04:58 +00:00
|
|
|
return TopShouts.top_authors[:limit]
|
2021-07-27 05:41:45 +00:00
|
|
|
|
|
|
|
|
2021-07-27 04:58:06 +00:00
|
|
|
@mutation.field("createShout")
|
|
|
|
@login_required
|
2021-08-08 12:23:12 +00:00
|
|
|
async def create_shout(_, info, input):
|
2021-07-27 04:58:06 +00:00
|
|
|
auth = info.context["request"].auth
|
|
|
|
user_id = auth.user_id
|
|
|
|
|
2021-08-08 09:49:15 +00:00
|
|
|
with local_session() as session:
|
|
|
|
user = session.query(User).filter(User.id == user_id).first()
|
2021-08-28 10:13:50 +00:00
|
|
|
|
|
|
|
new_shout = Shout.create(**input)
|
|
|
|
ShoutAuthor.create(
|
|
|
|
shout = new_shout.id,
|
|
|
|
user = user_id)
|
2021-08-08 09:49:15 +00:00
|
|
|
|
|
|
|
task = GitTask(
|
2021-08-08 12:23:12 +00:00
|
|
|
input,
|
2021-08-08 09:49:15 +00:00
|
|
|
user.username,
|
|
|
|
user.email,
|
2021-08-08 12:23:12 +00:00
|
|
|
"new shout %s" % (new_shout.slug)
|
2021-08-08 09:49:15 +00:00
|
|
|
)
|
|
|
|
|
2021-07-27 04:58:06 +00:00
|
|
|
return {
|
|
|
|
"shout" : new_shout
|
|
|
|
}
|
|
|
|
|
2021-08-17 09:14:26 +00:00
|
|
|
@mutation.field("updateShout")
|
|
|
|
@login_required
|
2021-08-28 10:13:50 +00:00
|
|
|
async def update_shout(_, info, id, input):
|
2021-08-17 09:14:26 +00:00
|
|
|
auth = info.context["request"].auth
|
|
|
|
user_id = auth.user_id
|
|
|
|
|
2021-08-28 15:12:13 +00:00
|
|
|
session = local_session()
|
|
|
|
user = session.query(User).filter(User.id == user_id).first()
|
|
|
|
shout = session.query(Shout).filter(Shout.id == id).first()
|
2021-08-17 09:14:26 +00:00
|
|
|
|
|
|
|
if not shout:
|
|
|
|
return {
|
|
|
|
"error" : "shout not found"
|
|
|
|
}
|
|
|
|
|
2021-08-28 15:12:13 +00:00
|
|
|
authors = [author.id for author in shout.authors]
|
|
|
|
if not user_id in authors:
|
2021-08-18 16:53:55 +00:00
|
|
|
scopes = auth.scopes
|
|
|
|
print(scopes)
|
|
|
|
if not Resource.shout_id in scopes:
|
2021-08-17 09:14:26 +00:00
|
|
|
return {
|
|
|
|
"error" : "access denied"
|
|
|
|
}
|
|
|
|
|
2021-08-28 15:12:13 +00:00
|
|
|
shout.update(input)
|
|
|
|
shout.updatedAt = datetime.now()
|
|
|
|
session.commit()
|
|
|
|
session.close()
|
2021-08-18 16:53:55 +00:00
|
|
|
|
2021-08-28 15:12:13 +00:00
|
|
|
for topic in input.get("topics"):
|
|
|
|
ShoutTopic.create(
|
|
|
|
shout = shout.id,
|
|
|
|
topic = topic)
|
2021-08-18 16:53:55 +00:00
|
|
|
|
|
|
|
task = GitTask(
|
|
|
|
input,
|
|
|
|
user.username,
|
|
|
|
user.email,
|
|
|
|
"update shout %s" % (shout.slug)
|
|
|
|
)
|
|
|
|
|
2021-08-17 09:14:26 +00:00
|
|
|
return {
|
|
|
|
"shout" : shout
|
|
|
|
}
|
2021-07-27 04:58:06 +00:00
|
|
|
|
2021-09-25 11:40:37 +00:00
|
|
|
@mutation.field("rateShout")
|
|
|
|
@login_required
|
|
|
|
async def rate_shout(_, info, shout_id, value):
|
|
|
|
auth = info.context["request"].auth
|
|
|
|
user_id = auth.user_id
|
|
|
|
|
|
|
|
with local_session() as session:
|
|
|
|
rating = session.query(ShoutRating).\
|
|
|
|
filter(and_(ShoutRating.rater_id == user_id, ShoutRating.shout_id == shout_id)).first()
|
|
|
|
if rating:
|
|
|
|
rating.value = value;
|
|
|
|
rating.ts = datetime.now()
|
|
|
|
session.commit()
|
|
|
|
else:
|
|
|
|
rating = ShoutRating.create(
|
|
|
|
rater_id = user_id,
|
|
|
|
shout_id = shout_id,
|
|
|
|
value = value
|
|
|
|
)
|
|
|
|
|
|
|
|
rating_storage.update_rating(rating)
|
|
|
|
|
|
|
|
return {"error" : ""}
|
|
|
|
|
2021-09-27 14:59:44 +00:00
|
|
|
@mutation.field("viewShout")
|
|
|
|
async def view_shout(_, info, shout_id):
|
2021-09-29 12:59:48 +00:00
|
|
|
await ShoutViewStorage.inc_view(shout_id)
|
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):
|
2021-09-25 11:40:37 +00:00
|
|
|
slug_fields = [node.name.value for node in info.field_nodes[0].selection_set.selections]
|
|
|
|
slug_fields = set(["authors", "comments", "topics"]).intersection(slug_fields)
|
|
|
|
select_options = [selectinload(getattr(Shout, field)) for field in slug_fields]
|
|
|
|
|
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()
|
|
|
|
shout.rating = rating_storage.get_rating(shout.id)
|
2021-09-29 12:59:48 +00:00
|
|
|
shout.views = await ShoutViewStorage.get_view(shout.id)
|
2021-09-05 08:56:15 +00:00
|
|
|
return shout
|