proposals and refactoring

This commit is contained in:
tonyrewin 2022-06-19 20:54:39 +03:00
parent 30c51ecac1
commit 11f81d46ce
9 changed files with 545 additions and 370 deletions

View File

@ -6,9 +6,13 @@ from orm.notification import Notification
from orm.shout import Shout, ShoutAuthor, ShoutTopic, ShoutRating, ShoutViewByDay,\
ShoutRatingStorage, ShoutViewStorage
from orm.base import Base, engine, local_session
from orm.comment import Comment, CommentRating
from orm.comment import Comment, CommentRating #, CommentRatingStorage
from orm.proposal import Proposal, ProposalRating #, ProposalRatingStorage
__all__ = ["User", "Role", "Community", "Operation", "Permission", "Shout", "Topic", "TopicSubscription", "Notification", "ShoutRating", "Comment", "CommentRating", "UserRating"]
__all__ = ["User", "Role", "Community", "Operation", \
"Permission", "Shout", "Topic", "TopicSubscription", \
"Notification", "ShoutRating", "Comment", "CommentRating", \
"UserRating", "Proposal", "ProposalRating"]
Base.metadata.create_all(engine)
Operation.init_table()
@ -19,6 +23,8 @@ Role.init_table()
with local_session() as session:
ShoutRatingStorage.init(session)
# CommentRatingStorage.init(session)
# ProposalRatingStorage.init(session)
ShoutViewStorage.init(session)
RoleStorage.init(session)
UserStorage.init(session)

View File

@ -1,23 +1,33 @@
from typing import List
from datetime import datetime
from sqlalchemy import Column, Integer, String, ForeignKey, Datetime
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime
from sqlalchemy.orm import relationship
from orm import Permission
from orm.base import Base
class Proposal(Base):
__tablename__ = 'proposal'
class ProposalRating(Base):
__tablename__ = "comment_rating"
shout: int = Column(Integer, ForeignKey("shout.id"), nullable=False, comment="Shout")
range: str = Column(String, nullable=True, comment="Range in format <start index>:<end>")
body: str = Column(String, nullable=False, comment="Body")
createdBy: int = Column(Integer, ForeignKey("user.id"), nullable=False, comment="Author")
createdAt: str = Column(datetime, nullable=False, comment="Created at")
updatedAt: str = Column(datetime, nullable=True, comment="Updated at")
acceptedAt: str = Column(datetime, nullable=True, comment="Accepted at")
acceptedBy: str = Column(datetime, nullable=True, comment="Accepted by")
deletedAt: str = Column(datetime, nullable=True, comment="Deleted at")
declinedAt: str = Column(datetime, nullable=True, comment="Declined at)
declinedBy: str = Column(datetime, nullable=True, comment="Declined by")
# TODO: debug, logix
id = None
proposal_id = Column(ForeignKey('proposal.id'), primary_key = True)
createdBy = Column(ForeignKey('user.slug'), primary_key = True)
createdAt: str = Column(DateTime, nullable=False, default = datetime.now, comment="Timestamp")
value = Column(Integer)
class Proposal(Base):
__tablename__ = 'proposal'
shout: str = Column(String, ForeignKey("shout.slug"), nullable=False, comment="Shout")
range: str = Column(String, nullable=True, comment="Range in format <start index>:<end>")
body: str = Column(String, nullable=False, comment="Body")
createdBy: int = Column(Integer, ForeignKey("user.id"), nullable=False, comment="Author")
createdAt: str = Column(DateTime, nullable=False, comment="Created at")
updatedAt: str = Column(DateTime, nullable=True, comment="Updated at")
acceptedAt: str = Column(DateTime, nullable=True, comment="Accepted at")
acceptedBy: str = Column(Integer, ForeignKey("user.id"), nullable=True, comment="Accepted by")
declinedAt: str = Column(DateTime, nullable=True, comment="Declined at")
declinedBy: str = Column(Integer, ForeignKey("user.id"), nullable=True, comment="Declined by")
ratings = relationship(ProposalRating, foreign_keys=ProposalRating.proposal_id)
deletedAt: str = Column(DateTime, nullable=True, comment="Deleted at")
# TODO: debug, logix

View File

@ -1,42 +1,74 @@
from resolvers.auth import login, sign_out, is_email_used, register, confirm
from resolvers.zine import create_shout, get_shout_by_slug, \
top_month, top_overall, recent_published, recent_all, top_viewed, \
shouts_by_authors, shouts_by_topics, shouts_by_communities, \
shouts_reviewed, shouts_subscribed
from resolvers.profile import get_users_by_slugs, get_current_user
from resolvers.auth import login, sign_out, is_email_used, register, confirm, auth_forget, auth_reset
from resolvers.zine import get_shout_by_slug, subscribe, unsubscribe, view_shout, rate_shout, \
top_month, top_overall, recent_published, recent_all, top_viewed, \
shouts_by_authors, shouts_by_topics, shouts_by_communities
from resolvers.profile import get_users_by_slugs, get_current_user, shouts_reviewed, shouts_subscribed
from resolvers.topics import topic_subscribe, topic_unsubscribe, topics_by_author, \
topics_by_community, topics_by_slugs
from resolvers.comments import create_comment
topics_by_community, topics_by_slugs
from resolvers.comments import create_comment, delete_comment, update_comment, rate_comment
from resolvers.collab import get_shout_proposals, create_proposal, delete_proposal, \
update_proposal, rate_proposal, decline_proposal, disable_proposal, accept_proposal
from resolvers.editor import create_shout, delete_shout, update_shout
from resolvers.community import create_community, delete_community, get_community, get_communities
__all__ = [
"login",
"register",
"is_email_used",
"confirm",
# TODO: "reset_password_code",
# TODO: "reset_password_confirm",
"create_shout",
"get_current_user",
"get_users_by_slugs",
"get_shout_by_slug",
"recent_published",
"recent_all",
"shouts_by_topics",
"shouts_by_authors",
"shouts_by_communities",
"shouts_subscribed",
"shouts_reviewed",
"top_month",
"top_overall",
"top_viewed",
"topics_by_slugs",
"topics_by_community",
"topics_by_author",
"topic_subscribe",
"topic_unsubscribe",
"create_community",
"delete_community",
"get_community",
"get_communities"
]
# auth
"login",
"register",
"is_email_used",
"confirm",
"auth_forget",
"auth_reset"
# profile
"get_current_user",
"get_users_by_slugs",
# zine
"recent_published",
"recent_all",
"shouts_by_topics",
"shouts_by_authors",
"shouts_by_communities",
"shouts_subscribed",
"shouts_reviewed",
"top_month",
"top_overall",
"top_viewed",
"rate_shout",
"view_shout",
"get_shout_by_slug",
# editor
"create_shout",
"update_shout",
"delete_shout",
# topics
"topics_by_slugs",
"topics_by_community",
"topics_by_author",
"topic_subscribe",
"topic_unsubscribe",
# communities
"get_community",
"get_communities",
"create_community",
"delete_community",
# comments
"get_shout_comments",
"create_comment",
"update_comment",
"delete_comment",
# collab
"get_shout_proposals",
"create_proposal",
"update_proposal",
"disable_proposal",
"accept_proposal",
"decline_proposal",
"delete_proposal"
]

View File

@ -18,6 +18,7 @@ from settings import JWT_AUTH_HEADER
@mutation.field("confirmEmail")
async def confirm(*_, confirm_token):
''' confirm owning email address '''
auth_token, user = await Authorize.confirm(confirm_token)
if auth_token:
user.emailConfirmed = True
@ -29,6 +30,7 @@ async def confirm(*_, confirm_token):
@mutation.field("registerUser")
async def register(*_, email: str, password: str = ""):
''' creates new user account '''
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
if user:
@ -51,7 +53,8 @@ async def register(*_, email: str, password: str = ""):
return { "user": user }
@mutation.field("requestPasswordUpdate")
async def request_password_update(_, info, email):
async def auth_forget(_, info, email):
''' send email to recover account '''
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
if not user:
@ -62,9 +65,10 @@ async def request_password_update(_, info, email):
return {}
@mutation.field("updatePassword")
async def update_password(_, info, password, token):
async def auth_reset(_, info, password, resetToken):
''' set the new password '''
try:
user_id = await ResetPassword.verify(token)
user_id = await ResetPassword.verify(resetToken)
except InvalidToken as e:
return {"error" : e.message}
@ -79,6 +83,7 @@ async def update_password(_, info, password, token):
@query.field("signIn")
async def login(_, info: GraphQLResolveInfo, email: str, password: str = ""):
with local_session() as session:
orm_user = session.query(User).filter(User.email == email).first()
if orm_user is None:
@ -126,4 +131,4 @@ async def sign_out(_, info: GraphQLResolveInfo):
async def is_email_used(_, info, email):
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
return not user is None
return not user is None

191
resolvers/collab.py Normal file
View File

@ -0,0 +1,191 @@
from orm import Proposal, ProposalRating, UserStorage
from orm.base import local_session
from resolvers.base import mutation, query, subscription
from auth.authenticate import login_required
import asyncio
from datetime import datetime
class ProposalResult:
def __init__(self, status, proposal):
self.status = status
self.proposal = proposal
@query.field("getShoutProposals")
@login_required
async def get_shout_proposals(_, info, slug):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposals = session.query(Proposal).\
options(selectinload(Proposal.ratings)).\
filter(Proposal.shout == slug).\
group_by(Proposal.id).all()
shout = session.query(Shout).filter(Shout.slug == slug).first()
authors = [author.id for author in shout.authors]
if user_id not in authors:
return {"error": "access denied"}
for proposal in proposals:
proposal.createdBy = await UserStorage.get_user(proposal.createdBy)
return proposals
@mutation.field("createProposal")
@login_required
async def create_proposal(_, info, body, shout, range = None):
auth = info.context["request"].auth
user_id = auth.user_id
proposal = Proposal.create(
createdBy = user_id,
body = body,
shout = shout,
range = range
)
result = ProposalResult("NEW", proposal)
await ProposalSubscriptions.put(result)
return {"proposal": proposal}
@mutation.field("updateProposal")
@login_required
async def update_proposal(_, info, id, body):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
shout = session.query(Shout).filter(Shout.sllug == proposal.shout).first()
authors = [author.id for author in shout.authors]
if not proposal:
return {"error": "invalid proposal id"}
if proposal.author in authors:
return {"error": "access denied"}
proposal.body = body
proposal.updatedAt = datetime.now()
session.commit()
result = ProposalResult("UPDATED", proposal)
await ProposalSubscriptions.put(result)
return {"proposal": proposal}
@mutation.field("deleteProposal")
@login_required
async def delete_proposal(_, info, id):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
if not proposal:
return {"error": "invalid proposal id"}
if proposal.createdBy != user_id:
return {"error": "access denied"}
proposal.deletedAt = datetime.now()
session.commit()
result = ProposalResult("DELETED", proposal)
await ProposalSubscriptions.put(result)
return {}
@mutation.field("disableProposal")
@login_required
async def disable_proposal(_, info, id):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
if not proposal:
return {"error": "invalid proposal id"}
if proposal.createdBy != user_id:
return {"error": "access denied"}
proposal.deletedAt = datetime.now()
session.commit()
result = ProposalResult("DISABLED", proposal)
await ProposalSubscriptions.put(result)
return {}
@mutation.field("rateProposal")
@login_required
async def rate_proposal(_, info, id, value):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
if not proposal:
return {"error": "invalid proposal id"}
rating = session.query(ProposalRating).\
filter(ProposalRating.proposal_id == id and ProposalRating.createdBy == user_id).first()
if rating:
rating.value = value
session.commit()
if not rating:
ProposalRating.create(
proposal_id = id,
createdBy = user_id,
value = value)
result = ProposalResult("UPDATED_RATING", proposal)
await ProposalSubscriptions.put(result)
return {}
@mutation.field("acceptProposal")
@login_required
async def accept_proposal(_, info, id):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
shout = session.query(Shout).filter(Shout.slug == proposal.shout).first()
authors = [author.id for author in shout.authors]
if not proposal:
return {"error": "invalid proposal id"}
if user_id not in authors:
return {"error": "access denied"}
proposal.acceptedAt = datetime.now()
proposal.acceptedBy = user_id
session.commit()
result = ProposalResult("ACCEPTED", proposal)
await ProposalSubscriptions.put(result)
return {}
@mutation.field("declineProposal")
@login_required
async def decline_proposal(_, info, id):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
shout = session.query(Shout).filter(Shout.slug == proposal.shout).first()
authors = [author.id for author in shout.authors]
if not proposal:
return {"error": "invalid proposal id"}
if user_id not in authors:
return {"error": "access denied"}
proposal.acceptedAt = datetime.now()
proposal.acceptedBy = user_id
session.commit()
result = ProposalResult("DECLINED", proposal)
await ProposalSubscriptions.put(result)
return {}

View File

@ -1,123 +1,109 @@
from orm import Proposal, ProposalRating
from orm import Shout, ShoutRating, ShoutRatingStorage
from orm.base import local_session
from resolvers.base import mutation, query, subscription
from auth.authenticate import login_required
import asyncio
from datetime import datetime
class ProposalResult:
def __init__(self, status, proposal):
self.status = status
self.proposal = proposal
@mutation.field("createProposal")
@mutation.field("createShout")
@login_required
async def create_proposal(_, info, body, shout, range = None):
async def create_shout(_, info, input):
user = info.context["request"].user
topic_slugs = input.get("topic_slugs", [])
if topic_slugs:
del input["topic_slugs"]
new_shout = Shout.create(**input)
ShoutAuthor.create(
shout = new_shout.slug,
user = user.slug)
if "mainTopic" in input:
topic_slugs.append(input["mainTopic"])
for slug in topic_slugs:
topic = ShoutTopic.create(
shout = new_shout.slug,
topic = slug)
new_shout.topic_slugs = topic_slugs
task = GitTask(
input,
user.username,
user.email,
"new shout %s" % (new_shout.slug)
)
await ShoutSubscriptions.send_shout(new_shout)
return {
"shout" : new_shout
}
@mutation.field("updateShout")
@login_required
async def update_shout(_, info, input):
auth = info.context["request"].auth
user_id = auth.user_id
proposal = Proposal.create(
createdBy = user_id,
body = body,
shout = shout,
range = range
slug = input["slug"]
session = local_session()
user = session.query(User).filter(User.id == user_id).first()
shout = session.query(Shout).filter(Shout.slug == slug).first()
if not shout:
return {
"error" : "shout not found"
}
authors = [author.id for author in shout.authors]
if not user_id in authors:
scopes = auth.scopes
print(scopes)
if not Resource.shout_id in scopes:
return {
"error" : "access denied"
}
shout.update(input)
shout.updatedAt = datetime.now()
session.commit()
session.close()
for topic in input.get("topic_slugs", []):
ShoutTopic.create(
shout = slug,
topic = topic)
task = GitTask(
input,
user.username,
user.email,
"update shout %s" % (slug)
)
result = ProposalResult("NEW", proposal)
await ProposalSubscriptions.put(result)
return {
"shout" : shout
}
return {"proposal": proposal}
@mutation.field("updateProposal")
@mutation.field("deleteShout")
@login_required
async def update_proposal(_, info, id, body):
async def delete_shout(_, info, slug):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
shout = session.query(Shout.slug === proposal.shout)
if not proposal:
return {"error": "invalid proposal id"}
if proposal.author != user_id:
return {"error": "access denied"}
proposal.body = body
proposal.updatedAt = datetime.now()
session.commit()
result = ProposalResult("UPDATED", proposal)
await ProposalSubscriptions.put(result)
return {"proposal": proposal}
@mutation.field("deleteProposal")
@login_required
async def delete_proposal(_, info, id):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
if not proposal:
return {"error": "invalid proposal id"}
if proposal.createdBy != user_id:
shout = session.query(Shout).filter(Shout.slug == slug).first()
authors = [author.id for author in shout.authors]
if not comment:
return {"error": "invalid shout slug"}
if user_id not in authors:
return {"error": "access denied"}
proposal.deletedAt = datetime.now()
shout.deletedAt = datetime.now()
session.commit()
result = ProposalResult("DELETED", proposal)
await ProposalSubscriptions.put(result)
return {}
@mutation.field("rateProposal")
@login_required
async def rate_proposal(_, info, id, value):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
if not proposal:
return {"error": "invalid proposal id"}
rating = session.query(ProposalRating).\
filter(ProposalRating.proposal_id == id and ProposalRating.createdBy == user_id).first()
if rating:
rating.value = value
session.commit()
if not rating:
ProposalRating.create(
proposal_id = id,
createdBy = user_id,
value = value)
result = ProposalResult("UPDATED_RATING", proposal)
await ProposalSubscriptions.put(result)
return {}
@mutation.field("acceptProposal")
@login_required
async def accept_proposal(_, info, id):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
proposal = session.query(Proposal).filter(Proposal.id == id).first()
if not proposal:
return {"error": "invalid proposal id"}
if proposal.acceptedBy == user_id: # TODO: manage ACL here to give access all editors
return {"error": "access denied"}
proposal.acceptedAt = datetime.now()
proposal.acceptedBy = user_id
session.commit()
result = ProposalResult("ACCEPTED", proposal)
await ProposalSubscriptions.put(result)
return {}
return {}

View File

@ -153,36 +153,95 @@ def author_unsubscribe(user, slug):
session.delete(sub)
session.commit()
@mutation.field("subscribe")
@query.field("shoutsRatedByUser")
@login_required
async def subscribe(_, info, subscription, slug):
async def shouts_rated_by_user(_, info, page, size):
user = info.context["request"].user
try:
if subscription == "AUTHOR":
author_subscribe(user, slug)
elif subscription == "TOPIC":
topic_subscribe(user, slug)
elif subscription == "COMMUNITY":
community_subscribe(user, slug)
except Exception as e:
return {"error" : e}
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutRating).\
where(ShoutRating.rater == user.slug).\
order_by(desc(ShoutRating.ts)).\
limit(size).\
offset( (page - 1) * size)
return {}
return {
"shouts" : shouts
}
@mutation.field("unsubscribe")
@query.field("userUnpublishedShouts")
@login_required
async def unsubscribe(_, info, subscription, slug):
async def user_unpublished_shouts(_, info, page, size):
user = info.context["request"].user
try:
if subscription == "AUTHOR":
author_unsubscribe(user, slug)
elif subscription == "TOPIC":
topic_unsubscribe(user, slug)
elif subscription == "COMMUNITY":
community_unsubscribe(user, slug)
except Exception as e:
return {"error" : e}
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutAuthor).\
where(and_(Shout.publishedAt == None, ShoutAuthor.user == user.slug)).\
order_by(desc(Shout.createdAt)).\
limit(size).\
offset( (page - 1) * size)
return {
"shouts" : shouts
}
@query.field("shoutsReviewed")
@login_required
async def shouts_reviewed(_, info, page, size):
user = info.context["request"].user
with local_session() as session:
shouts_by_rating = session.query(Shout).\
join(ShoutRating).\
where(and_(Shout.publishedAt != None, ShoutRating.rater == user.slug))
shouts_by_comment = session.query(Shout).\
join(Comment).\
where(and_(Shout.publishedAt != None, Comment.author == user.id))
shouts = shouts_by_rating.union(shouts_by_comment).\
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset( (page - 1) * size)
return shouts
@query.field("shoutsSubscribed")
@login_required
async def shouts_subscribed(_, info, page, size):
user = info.context["request"].user
with local_session() as session:
shouts_by_topic = session.query(Shout).\
join(ShoutTopic).\
join(TopicSubscription, ShoutTopic.topic == TopicSubscription.topic).\
where(TopicSubscription.subscriber == user.slug)
shouts_by_author = session.query(Shout).\
join(ShoutAuthor).\
join(AuthorSubscription, ShoutAuthor.user == AuthorSubscription.author).\
where(AuthorSubscription.subscriber == user.slug)
shouts_by_community = session.query(Shout).\
join(Community).\
join(CommunitySubscription).\
where(CommunitySubscription.subscriber == user.slug)
shouts = shouts_by_topic.union(shouts_by_author).\
union(shouts_by_community).\
order_by(desc(Shout.createdAt)).\
limit(size).\
offset( (page - 1) * size)
return shouts
@query.field("shoutsCommentedByUser")
async def shouts_commented_by_user(_, info, slug, page, size):
user = await UserStorage.get_user_by_slug(slug)
if not user:
return {}
with local_session() as session:
shouts = session.query(Shout).\
join(Comment).\
where(Comment.author == user.id).\
order_by(desc(Comment.createdAt)).\
limit(size).\
offset( (page - 1) * size)
return shouts
return {}

View File

@ -257,113 +257,6 @@ async def recent_commented(_, info, page, size):
async with ShoutsCache.lock:
return ShoutsCache.recent_commented[(page - 1) * size : page * size]
@mutation.field("createShout")
@login_required
async def create_shout(_, info, input):
user = info.context["request"].user
topic_slugs = input.get("topic_slugs", [])
if topic_slugs:
del input["topic_slugs"]
new_shout = Shout.create(**input)
ShoutAuthor.create(
shout = new_shout.slug,
user = user.slug)
if "mainTopic" in input:
topic_slugs.append(input["mainTopic"])
for slug in topic_slugs:
topic = ShoutTopic.create(
shout = new_shout.slug,
topic = slug)
new_shout.topic_slugs = topic_slugs
task = GitTask(
input,
user.username,
user.email,
"new shout %s" % (new_shout.slug)
)
await ShoutSubscriptions.send_shout(new_shout)
return {
"shout" : new_shout
}
@mutation.field("updateShout")
@login_required
async def update_shout(_, info, input):
auth = info.context["request"].auth
user_id = auth.user_id
slug = input["slug"]
session = local_session()
user = session.query(User).filter(User.id == user_id).first()
shout = session.query(Shout).filter(Shout.slug == slug).first()
if not shout:
return {
"error" : "shout not found"
}
authors = [author.id for author in shout.authors]
if not user_id in authors:
scopes = auth.scopes
print(scopes)
if not Resource.shout_id in scopes:
return {
"error" : "access denied"
}
shout.update(input)
shout.updatedAt = datetime.now()
session.commit()
session.close()
for topic in input.get("topic_slugs", []):
ShoutTopic.create(
shout = slug,
topic = topic)
task = GitTask(
input,
user.username,
user.email,
"update shout %s" % (slug)
)
return {
"shout" : shout
}
@mutation.field("rateShout")
@login_required
async def rate_shout(_, info, slug, value):
auth = info.context["request"].auth
user = info.context["request"].user
with local_session() as session:
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
)
await ShoutRatingStorage.update_rating(rating)
return {"error" : ""}
@mutation.field("viewShout")
async def view_shout(_, info, slug):
await ShoutViewStorage.inc_view(slug)
@ -439,94 +332,61 @@ async def shouts_by_communities(_, info, slugs, page, size):
offset(page * size)
return shouts
@query.field("shoutsSubscribed")
@mutation.field("subscribe")
@login_required
async def shouts_subscribed(_, info, page, size):
async def subscribe(_, info, subscription, slug):
user = info.context["request"].user
with local_session() as session:
shouts_by_topic = session.query(Shout).\
join(ShoutTopic).\
join(TopicSubscription, ShoutTopic.topic == TopicSubscription.topic).\
where(TopicSubscription.subscriber == user.slug)
shouts_by_author = session.query(Shout).\
join(ShoutAuthor).\
join(AuthorSubscription, ShoutAuthor.user == AuthorSubscription.author).\
where(AuthorSubscription.subscriber == user.slug)
shouts_by_community = session.query(Shout).\
join(Community).\
join(CommunitySubscription).\
where(CommunitySubscription.subscriber == user.slug)
shouts = shouts_by_topic.union(shouts_by_author).\
union(shouts_by_community).\
order_by(desc(Shout.createdAt)).\
limit(size).\
offset( (page - 1) * size)
return shouts
try:
if subscription == "AUTHOR":
author_subscribe(user, slug)
elif subscription == "TOPIC":
topic_subscribe(user, slug)
elif subscription == "COMMUNITY":
community_subscribe(user, slug)
except Exception as e:
return {"error" : e}
@query.field("shoutsReviewed")
return {}
@mutation.field("unsubscribe")
@login_required
async def shouts_reviewed(_, info, page, size):
async def unsubscribe(_, info, subscription, slug):
user = info.context["request"].user
with local_session() as session:
shouts_by_rating = session.query(Shout).\
join(ShoutRating).\
where(and_(Shout.publishedAt != None, ShoutRating.rater == user.slug))
shouts_by_comment = session.query(Shout).\
join(Comment).\
where(and_(Shout.publishedAt != None, Comment.author == user.id))
shouts = shouts_by_rating.union(shouts_by_comment).\
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset( (page - 1) * size)
return shouts
try:
if subscription == "AUTHOR":
author_unsubscribe(user, slug)
elif subscription == "TOPIC":
topic_unsubscribe(user, slug)
elif subscription == "COMMUNITY":
community_unsubscribe(user, slug)
except Exception as e:
return {"error" : e}
@query.field("shoutsCommentedByUser")
async def shouts_commented_by_user(_, info, slug, page, size):
user = await UserStorage.get_user_by_slug(slug)
if not user:
return {}
return {}
with local_session() as session:
shouts = session.query(Shout).\
join(Comment).\
where(Comment.author == user.id).\
order_by(desc(Comment.createdAt)).\
limit(size).\
offset( (page - 1) * size)
return shouts
@query.field("shoutsRatedByUser")
@mutation.field("rateShout")
@login_required
async def shouts_rated_by_user(_, info, page, size):
async def rate_shout(_, info, slug, value):
auth = info.context["request"].auth
user = info.context["request"].user
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutRating).\
where(ShoutRating.rater == user.slug).\
order_by(desc(ShoutRating.ts)).\
limit(size).\
offset( (page - 1) * size)
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
)
return {
"shouts" : shouts
}
await ShoutRatingStorage.update_rating(rating)
@query.field("userUnpublishedShouts")
@login_required
async def user_unpublished_shouts(_, info, page, size):
user = info.context["request"].user
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutAuthor).\
where(and_(Shout.publishedAt == None, ShoutAuthor.user == user.slug)).\
order_by(desc(Shout.createdAt)).\
limit(size).\
offset( (page - 1) * size)
return {
"shouts" : shouts
}
return {"error" : ""}

View File

@ -126,15 +126,26 @@ type Mutation {
createTopic(input: TopicInput!): TopicResult!
updateTopic(input: TopicInput!): TopicResult!
# comments
createComment(body: String!, shout: String!, replyTo: Int): CommentResult!
updateComment(id: Int!, body: String!): CommentResult!
deleteComment(id: Int!): Result!
rateComment(id: Int!, value: Int!): Result!
# community
createCommunity(title: String!, desc: String!): Community!
updateCommunity(community: CommunityInput!): Community!
deleteCommunity(id: Int!): Result!
# proposal
createProposal(body: String!, range: String): Proposal!
updateProposal(body: String!, range: String): Proposal!
acceptProposal(id: Int!): Result!
declineProposal(id: Int!): Result!
disableProposal(id: Int!): Result!
deleteProposal(id: Int!): Result!
rateProposal(id: Int!): Result!
subscribe(what: SubscriptionType!, slug: String!): Result!
unsubscribe(what: SubscriptionType!, slug: String!): Result!
}
@ -167,6 +178,9 @@ type Query {
shoutsByCommunities(slugs: [String]!, page: Int!, size: Int!): [Shout]!
getShoutComments(slug: String!): [Comment]!
# collab
getShoutProposals(slug: String!): [Proposal]!
# mainpage
topViewed(page: Int!, size: Int!): [Shout]!
topMonth(page: Int!, size: Int!): [Shout]!
@ -353,17 +367,29 @@ type Topic {
topicStat: TopicStat
}
enum ProposalStatus {
NEW
UPDATED
UPDATED_RATING
ACCEPTED
DECLINED
DISABLED
DELETED
}
type Proposal {
createdBy: String!
shout: string!
shout: String!
range: String # full / 0:2340
body: String!
createdAt: DateTime!
createdBy: String!
updatedAt: DateTime
acceptedAt: DateTime
acceptedBy: string
acceptedBy: Int
declinedAt: DateTime
declinedBy: string
declinedBy: Int
disabledAt: DateTime
disabledBy: Int
}
type Token {