diff --git a/orm/draft.py b/orm/draft.py index 87ee3a8a..6b97e5c3 100644 --- a/orm/draft.py +++ b/orm/draft.py @@ -1,22 +1,31 @@ from datetime import datetime -from sqlalchemy import Column, ForeignKey, DateTime, String +from sqlalchemy import Boolean, Column, ForeignKey, DateTime, String from sqlalchemy.orm import relationship from base.orm import Base from orm.user import User +from orm.topic import Topic + + +class DraftTopic(Base): + __tablename__ = "draft_topic" + + id = None # type: ignore + collab = Column(ForeignKey("draft_collab.id"), primary_key=True) + topic = Column(ForeignKey("topic.id"), primary_key=True) class DraftAuthor(Base): - __tablename__ = "collab_author" + __tablename__ = "draft_author" id = None # type: ignore - collab = Column(ForeignKey("collab.id"), primary_key=True) + collab = Column(ForeignKey("draft_collab.id"), primary_key=True) author = Column(ForeignKey("user.id"), primary_key=True) - # accepted = Column(Boolean, default=False) + accepted = Column(Boolean, default=False) class DraftCollab(Base): - __tablename__ = "draftcollab" + __tablename__ = "draft_collab" slug = Column(String, nullable=True, comment="Slug") title = Column(String, nullable=True, comment="Title") @@ -25,8 +34,7 @@ class DraftCollab(Base): body = Column(String, nullable=True, comment="Body") cover = Column(String, nullable=True, comment="Cover") authors = relationship(lambda: User, secondary=DraftAuthor.__tablename__) - topics = relationship(lambda: Topic, secondary=ShoutTopic.__tablename__) - invites = relationship(lambda: User, secondary=CollabInvited.__tablename__) + topics = relationship(lambda: Topic, secondary=DraftTopic.__tablename__) createdAt = Column(DateTime, default=datetime.now, comment="Created At") updatedAt = Column(DateTime, default=datetime.now, comment="Updated At") chat = Column(String, unique=True, nullable=True) diff --git a/resolvers/__init__.py b/resolvers/__init__.py index e35f8ba4..5837f767 100644 --- a/resolvers/__init__.py +++ b/resolvers/__init__.py @@ -8,7 +8,8 @@ from resolvers.auth import ( get_current_user, ) -from resolvers.create.collab import remove_coauthor, invite_coauthor +from resolvers.create.collab import load_drafts, create_draft, update_draft, delete_draft,\ + accept_coauthor, invite_coauthor from resolvers.create.migrate import markdown_body from resolvers.create.editor import create_shout, delete_shout, update_shout @@ -93,8 +94,12 @@ __all__ = [ # create.migrate "markdown_body", # create.collab + "load_drafts", + "create_draft", + "update_draft", + "delete_draft", "invite_coauthor", - "remove_coauthor", + "accept_coauthor", # zine.topics "topics_all", "topics_by_community", diff --git a/resolvers/create/collab.py b/resolvers/create/collab.py index 74356a29..3fe4a169 100644 --- a/resolvers/create/collab.py +++ b/resolvers/create/collab.py @@ -3,33 +3,33 @@ from auth.credentials import AuthCredentials from base.orm import local_session from base.resolvers import query, mutation from base.exceptions import ObjectNotExist, BaseHttpException -from orm.draft import DraftCollab, CollabAuthor +from orm.draft import DraftCollab, DraftAuthor, DraftTopic from orm.shout import Shout from orm.user import User -# TODO: use updatedAt - - @query.field("loadDrafts") @login_required -async def get_drafts(_, info): +async def load_drafts(_, info): auth: AuthCredentials = info.context["request"].auth drafts = [] with local_session() as session: drafts = session.query(DraftCollab).filter(auth.user_id in DraftCollab.authors) - return { - "drafts": drafts - } + return drafts @mutation.field("createDraft") # TODO @login_required -async def create_draft(_, info): +async def create_draft(_, info, draft_input): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - pass + collab = DraftCollab.create(**draft_input) + session.add(collab) + session.commit() + + # TODO: email notify to all authors + return {} @mutation.field("deleteDraft") # TODO @@ -38,15 +38,29 @@ async def delete_draft(_, info, draft: int = 0): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - pass + collab = session.query(DraftCollab).where(DraftCollab.id == draft_input.id).one() + if auth.user_id not in s.authors: + # raise BaseHttpException("only owner can remove coauthors") + return { + "error": "Only authors can update a draft" + } + elif not collab: + return { + "error": "There is no draft with this id" + } + else: + session.delete(collab) + session.commit() + return {} -@mutation.field("updateDraft") # TODO + +@mutation.field("updateDraft") # TODO: draft input type @login_required -async def update_draft(_, info, author: int = 0, draft: int = 0): +async def update_draft(_, info, draft_input): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - s = session.query(DraftCollab).where(DraftCollab.id == draft).one() # raises Error when not found + collab = session.query(DraftCollab).where(DraftCollab.id == draft_input.id).one() # raises Error when not found if auth.user_id not in s.authors: # raise BaseHttpException("only owner can remove coauthors") return { @@ -57,12 +71,8 @@ async def update_draft(_, info, author: int = 0, draft: int = 0): "error": "There is no draft with this id" } else: - c = session.query(DraftCollab).where(DraftCollab.id == draft).one() - ca = session.query(CollabAuthor).join(User).where(c.id == draft).filter(User.id == author).one() - session.remve(ca) - c.invites = filter(lambda x: x.id == author, c.invites) - c.authors = filter(lambda x: x.id == author, c.authors) - session.add(c) + draft_input["updatedAt"] = datetime.now(tz=timezone.utc) + collab.update(**draft_input) session.commit() # TODO: email notify @@ -80,11 +90,19 @@ async def invite_coauthor(_, info, author: int = 0, draft: int = 0): return { "error": "You are not in authors list" } - else: + elif c.id: invited_user = session.query(User).where(User.id == author).one() - c.invites.append(invited_user) - session.add(c) + da = DraftAuthor.create({ + "accepted": False, + "collab": c.id, + "author": invited_user.id + }) + session.add(da) session.commit() + else: + return { + "error": "Draft is not found" + } # TODO: email notify return {} @@ -96,13 +114,17 @@ async def accept_coauthor(_, info, draft: int): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - c = session.query(DraftCollab).where(DraftCollab.id == draft).one() - accepted = filter(lambda x: x.id == auth.user_id, c.invites).pop() - if accepted: - c.authors.append(accepted) - session.add(c) + # c = session.query(DraftCollab).where(DraftCollab.id == draft).one() + a = session.query(DraftAuthor).where(DraftAuthor.collab == draft).filter(DraftAuthor.author == auth.user_id).one() + if not a.accepted: + a.accepted = True session.commit() + # TODO: email notify return {} + elif a.accepted == True: + return { + "error": "You have accepted invite before" + } else: # raise BaseHttpException("only invited can accept") return { diff --git a/resolvers/create/editor.py b/resolvers/create/editor.py index 84d744a4..a2b321ca 100644 --- a/resolvers/create/editor.py +++ b/resolvers/create/editor.py @@ -14,7 +14,7 @@ from resolvers.zine.reactions import reactions_follow, reactions_unfollow from services.zine.gittask import GitTask from resolvers.inbox.chats import create_chat from services.inbox.storage import MessagesStorage -from orm.collab import Collab +from orm.draft import DraftCollab @mutation.field("createShout") diff --git a/resolvers/zine/profile.py b/resolvers/zine/profile.py index 580e5b9e..8cd68453 100644 --- a/resolvers/zine/profile.py +++ b/resolvers/zine/profile.py @@ -219,10 +219,13 @@ def author_unfollow(user_id, slug): ).first() ) if not flw: - raise Exception("[resolvers.profile] follower not exist, cant unfollow") + return { + "error": "Follower is not exist, cant unfollow" + } else: session.delete(flw) session.commit() + return {} @query.field("authorsAll") diff --git a/schema.graphql b/schema.graphql index 8c23a618..080cb371 100644 --- a/schema.graphql +++ b/schema.graphql @@ -69,6 +69,7 @@ type Result { members: [ChatMember] shout: Shout shouts: [Shout] + drafts: [DraftCollab] author: Author authors: [Author] reaction: Reaction @@ -538,10 +539,16 @@ type Chat { private: Boolean } -type Collab { - authors: [String]! - invites: [String] - shout: Shout +type DraftCollab { + slug: String + title: String + subtitle: String + body: String + cover: String + layout: String + authors: [Int]! + topics: [String] chat: Chat createdAt: Int! + updatedAt: Int }