From 92b1eae9328683b15bef16b502ad99a85c6b701a Mon Sep 17 00:00:00 2001 From: tonyrewin Date: Wed, 11 Jan 2023 18:16:21 +0300 Subject: [PATCH 1/6] fix slug-id --- resolvers/zine/reactions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resolvers/zine/reactions.py b/resolvers/zine/reactions.py index 2b004578..40c912a5 100644 --- a/resolvers/zine/reactions.py +++ b/resolvers/zine/reactions.py @@ -171,7 +171,7 @@ async def update_reaction(_, info, reaction={}): if not r: return {"error": "invalid reaction id"} - if r.createdBy != user.slug: + if r.createdBy != user.id: return {"error": "access denied"} r.body = reaction["body"] @@ -202,7 +202,7 @@ async def delete_reaction(_, info, reaction=None): r = session.query(Reaction).filter(Reaction.id == reaction).first() if not r: return {"error": "invalid reaction id"} - if r.createdBy != user.slug: + if r.createdBy != user.id: return {"error": "access denied"} r.deletedAt = datetime.now(tz=timezone.utc) session.commit() From 2017be82eebb41641e3e82fcb4ca46c11205d174 Mon Sep 17 00:00:00 2001 From: tonyrewin Date: Fri, 13 Jan 2023 14:04:45 +0300 Subject: [PATCH 2/6] init --- orm/collab.py | 27 --------- orm/draft.py | 32 ++++++++++ orm/shout.py | 2 +- resolvers/create/collab.py | 116 ++++++++++++++++++++++--------------- schema.graphql | 25 ++++++-- 5 files changed, 122 insertions(+), 80 deletions(-) delete mode 100644 orm/collab.py create mode 100644 orm/draft.py diff --git a/orm/collab.py b/orm/collab.py deleted file mode 100644 index aa71004c..00000000 --- a/orm/collab.py +++ /dev/null @@ -1,27 +0,0 @@ -from datetime import datetime - -from sqlalchemy import Column, ForeignKey, DateTime, String -from sqlalchemy.orm import relationship -from base.orm import Base -from orm.user import User - - -class CollabAuthor(Base): - __tablename__ = "collab_author" - - id = None # type: ignore - collab = Column(ForeignKey("collab.id"), primary_key=True) - author = Column(ForeignKey("user.id"), primary_key=True) - # accepted = Column(Boolean, default=False) - - -class Collab(Base): - __tablename__ = "collab" - - title = Column(String, nullable=True, comment="Title") - body = Column(String, nullable=True, comment="Body") - pic = Column(String, nullable=True, comment="Picture") - authors = relationship(lambda: User, secondary=CollabAuthor.__tablename__) - # invites = relationship(lambda: User, secondary=CollabInvited.__tablename__) - createdAt = Column(DateTime, default=datetime.now, comment="Created At") - chat = Column(String, unique=True, nullable=False) diff --git a/orm/draft.py b/orm/draft.py new file mode 100644 index 00000000..87ee3a8a --- /dev/null +++ b/orm/draft.py @@ -0,0 +1,32 @@ +from datetime import datetime + +from sqlalchemy import Column, ForeignKey, DateTime, String +from sqlalchemy.orm import relationship +from base.orm import Base +from orm.user import User + + +class DraftAuthor(Base): + __tablename__ = "collab_author" + + id = None # type: ignore + collab = Column(ForeignKey("collab.id"), primary_key=True) + author = Column(ForeignKey("user.id"), primary_key=True) + # accepted = Column(Boolean, default=False) + + +class DraftCollab(Base): + __tablename__ = "draftcollab" + + slug = Column(String, nullable=True, comment="Slug") + title = Column(String, nullable=True, comment="Title") + subtitle = Column(String, nullable=True, comment="Subtitle") + layout = Column(String, nullable=True, comment="Layout format") + 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__) + 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/orm/shout.py b/orm/shout.py index 55435d5f..04b0102b 100644 --- a/orm/shout.py +++ b/orm/shout.py @@ -50,7 +50,7 @@ class Shout(Base): subtitle = Column(String, nullable=True) layout = Column(String, nullable=True) mainTopic = Column(ForeignKey("topic.slug"), nullable=True) - cover = Column(String, nullable=True) + cover = Column(String, nullable=True, comment="Cover") authors = relationship(lambda: User, secondary=ShoutAuthor.__tablename__) topics = relationship(lambda: Topic, secondary=ShoutTopic.__tablename__) reactions = relationship(lambda: Reaction) diff --git a/resolvers/create/collab.py b/resolvers/create/collab.py index c51c9be2..74356a29 100644 --- a/resolvers/create/collab.py +++ b/resolvers/create/collab.py @@ -3,56 +3,62 @@ 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.collab import Collab, CollabAuthor +from orm.draft import DraftCollab, CollabAuthor from orm.shout import Shout from orm.user import User -@query.field("getCollabs") +# TODO: use updatedAt + + +@query.field("loadDrafts") @login_required -async def get_collabs(_, info): +async def get_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 + } + + +@mutation.field("createDraft") # TODO +@login_required +async def create_draft(_, info): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - collabs = session.query(Collab).filter(auth.user_id in Collab.authors) - return collabs + pass -@mutation.field("inviteCoauthor") +@mutation.field("deleteDraft") # TODO @login_required -async def invite_coauthor(_, info, author: int = 0, shout: int = 0): +async def delete_draft(_, info, draft: int = 0): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - s = session.query(Shout).where(Shout.id == shout).one() - if not s: - raise ObjectNotExist("invalid shout id") - else: - c = session.query(Collab).where(Collab.shout == shout).one() - if auth.user_id not in c.authors: - raise BaseHttpException("you are not in authors list") - else: - invited_user = session.query(User).where(User.id == author).one() - c.invites.append(invited_user) - session.add(c) - session.commit() + pass - # TODO: email notify - return {} - - -@mutation.field("removeCoauthor") +@mutation.field("updateDraft") # TODO @login_required -async def remove_coauthor(_, info, author: int = 0, shout: int = 0): +async def update_draft(_, info, author: int = 0, draft: int = 0): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - s = session.query(Shout).where(Shout.id == shout).one() # raises Error when not found + s = session.query(DraftCollab).where(DraftCollab.id == draft).one() # raises Error when not found if auth.user_id not in s.authors: - raise BaseHttpException("only owner can remove coauthors") + # raise BaseHttpException("only owner can remove coauthors") + return { + "error": "Only authors can update draft" + } + elif not s: + return { + "error": "There is no draft with this id" + } else: - c = session.query(Collab).where(Collab.shout == shout).one() - ca = session.query(CollabAuthor).join(User).where(c.shout == shout, User.id == author).one() + 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) @@ -62,25 +68,43 @@ async def remove_coauthor(_, info, author: int = 0, shout: int = 0): # TODO: email notify return {} - -@mutation.field("acceptCoauthor") +@mutation.field("inviteAuthor") @login_required -async def accept_coauthor(_, info, shout: int): +async def invite_coauthor(_, info, author: int = 0, draft: int = 0): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - s = session.query(Shout).where(Shout.id == shout).one() - if not s: - raise ObjectNotExist("invalid shout id") + c = session.query(DraftCollab).where(DraftCollab.id == draft).one() + if auth.user_id not in c.authors: + # raise BaseHttpException("you are not in authors list") + return { + "error": "You are not in authors list" + } else: - c = session.query(Collab).where(Collab.shout == shout).one() - accepted = filter(lambda x: x.id == auth.user_id, c.invites).pop() - if accepted: - c.authors.append(accepted) - s.authors.append(accepted) - session.add(s) - session.add(c) - session.commit() - return {} - else: - raise BaseHttpException("only invited can accept") + invited_user = session.query(User).where(User.id == author).one() + c.invites.append(invited_user) + session.add(c) + session.commit() + + # TODO: email notify + return {} + + +@mutation.field("inviteAccept") +@login_required +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) + session.commit() + return {} + else: + # raise BaseHttpException("only invited can accept") + return { + "error": "You don't have an invitation yet" + } diff --git a/schema.graphql b/schema.graphql index 015f2b02..8c23a618 100644 --- a/schema.graphql +++ b/schema.graphql @@ -128,6 +128,17 @@ input TopicInput { # parents: [String] } +input DraftInput { + slug: String + topics: [Int] + authors: [Int] + title: String + subtitle: String + body: String + cover: String + +} + input ReactionInput { kind: ReactionKind! shout: Int! @@ -189,10 +200,12 @@ type Mutation { updateReaction(reaction: ReactionInput!): Result! deleteReaction(reaction: Int!): Result! - # collab - inviteCoauthor(author: String!, shout: Int!): Result! - removeCoauthor(author: String!, shout: Int!): Result! - acceptCoauthor(shout: Int!): Result! + # draft / collab + createDraft(draft: DraftInput!): Result! + updateDraft(draft: DraftInput!): Result! + deleteDraft(draft: Int!): Result! + inviteAccept(draft: Int!): Result! + inviteAuthor(draft: Int!, author: Int!): Result! # following follow(what: FollowingEntity!, slug: String!): Result! @@ -289,8 +302,8 @@ type Query { authorsAll: [Author]! getAuthor(slug: String!): User - # collab - getCollabs: [Collab]! + # draft/collab + loadDrafts: [DraftCollab]! # migrate markdownBody(body: String!): String! From 261b22716b1c3f09122055f3ff063be51d4d8d93 Mon Sep 17 00:00:00 2001 From: tonyrewin Date: Mon, 16 Jan 2023 11:32:36 +0300 Subject: [PATCH 3/6] drafts-orm-struct --- orm/draft.py | 22 +++++++---- resolvers/__init__.py | 9 ++++- resolvers/create/collab.py | 78 ++++++++++++++++++++++++-------------- resolvers/create/editor.py | 2 +- resolvers/zine/profile.py | 5 ++- schema.graphql | 15 ++++++-- 6 files changed, 88 insertions(+), 43 deletions(-) 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 } From 910c191b0dde9526d2c04db4485c4a5a866179e0 Mon Sep 17 00:00:00 2001 From: tonyrewin Date: Tue, 17 Jan 2023 09:19:12 +0300 Subject: [PATCH 4/6] proto --- migration/__init__.py | 17 +++++++++++++ migration/tables/remarks.py | 32 +++++++++++++++++++++++++ orm/remark.py | 15 ++++++++++++ resolvers/zine/remark.py | 48 +++++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 migration/tables/remarks.py create mode 100644 orm/remark.py create mode 100644 resolvers/zine/remark.py diff --git a/migration/__init__.py b/migration/__init__.py index a998ad07..0737f6c5 100644 --- a/migration/__init__.py +++ b/migration/__init__.py @@ -11,6 +11,7 @@ from migration.tables.content_items import get_shout_slug from migration.tables.content_items import migrate as migrateShout from migration.tables.topics import migrate as migrateTopic from migration.tables.users import migrate as migrateUser +from migration.tables.remarks import migrate as migrateRemark from migration.tables.users import migrate_2stage as migrateUser_2stage from orm.reaction import Reaction from orm import init_tables @@ -135,6 +136,15 @@ async def shouts_handle(storage, args): print("[migration] " + str(anonymous_author) + " authored by @anonymous") +async def remarks_handle(storage): + print("[migration] comments") + c = 0 + for entry_remark in storage["remarks"]["data"]: + remark = await migrateRemark(entry_remark) + c += 1 + print("[migration] " + str(c) + " remarks migrated") + + async def comments_handle(storage): print("[migration] comments") id_map = {} @@ -169,6 +179,8 @@ async def all_handle(storage, args): await users_handle(storage) await topics_handle(storage) print("[migration] users and topics are migrated") + await remarks_handle(storage) + print("[migration] remarks are migrated") await shouts_handle(storage, args) print("[migration] migrating comments") await comments_handle(storage) @@ -210,6 +222,11 @@ def data_load(): content_data = json.loads(open("migration/data/content_items.json").read()) storage["shouts"]["data"] = content_data print("[migration.load] " + str(len(content_data)) + " content items ") + + remarks_data = json.loads(open("migration/data/remarks.json").read()) + storage["remarks"]["data"] = remarks_data + print("[migration.load] " + str(len(remarks_data)) + " remarks data ") + # fill out storage for x in users_data: storage["users"]["by_oid"][x["_id"]] = x diff --git a/migration/tables/remarks.py b/migration/tables/remarks.py new file mode 100644 index 00000000..1b6b6350 --- /dev/null +++ b/migration/tables/remarks.py @@ -0,0 +1,32 @@ +from base.orm import local_session +from migration.extract import extract_md +from migration.html2text import html2text +from orm.remark import Remark + + +def migrate(entry): + print(entry) + break + remark = { + "slug": entry["slug"], + "oid": entry["_id"], + "body": extract_md(html2text( + entry['body'] + entry['textAfter'] or '' + \ + entry['textBefore'] or '' + \ + entry['textSelected'] or '' + ), entry["_id"]) + } + + with local_session() as session: + slug = remark["slug"] + rmrk = session.query(Remark).filter(Remark.slug == slug).first() or Remark.create( + **tooltip + ) + if not rmrk: + raise Exception("no rmrk!") + if rmrk: + Remark.update(rmrk, remark) + session.commit() + rt = tt.__dict__.copy() + del rt["_sa_instance_state"] + return rt diff --git a/orm/remark.py b/orm/remark.py new file mode 100644 index 00000000..89a6494a --- /dev/null +++ b/orm/remark.py @@ -0,0 +1,15 @@ +from datetime import datetime +from enum import Enum as Enumeration + +from sqlalchemy import Column, DateTime, Enum, ForeignKey, String + +from base.orm import Base + + +class Remark(Base): + + tablename = "remark" + + slug = Column(String, unique=True, nullable=False) + body = Column(String, nullable=False) + shout = Column(ForeignKey("shout.id"), nullable=True, index=True, comment="Shout") diff --git a/resolvers/zine/remark.py b/resolvers/zine/remark.py new file mode 100644 index 00000000..6f5f9d48 --- /dev/null +++ b/resolvers/zine/remark.py @@ -0,0 +1,48 @@ + +from datetime import datetime, timedelta, timezone +from sqlalchemy.orm import joinedload, aliased +from sqlalchemy.sql.expression import desc, asc, select, func +from base.orm import local_session +from base.resolvers import query, mutation +from base.exceptions import ObjectNotExist +from orm.remark import Remark + + +@mutation.field("createRemark") +@login_required +async def create_remark(_, info, slug, body): + auth = info.context["request"].auth + user_id = auth.user_id + with local_session() as session: + tt = Remark.create(slug=slug, body=body) + session.commit() + return + +@mutation.field("updateRemark") +@login_required +async def update_remark(_, info, slug, body = ''): + auth = info.context["request"].auth + user_id = auth.user_id + with local_session() as session: + rmrk = session.query(Remark).where(Remark.slug == slug).one() + if body: + tt.body = body + session.add(rmrk) + session.commit() + return + +@mutation.field("deleteRemark") +@login_required +async def delete_remark(_, info, slug): + auth = info.context["request"].auth + user_id = auth.user_id + with local_session() as session: + rmrk = session.query(Remark).where(Remark.slug == slug).one() + rmrk.remove() + session.commit() + return + +@query.field("loadRemark") +@login_required +async def load_remark(_, info, slug): + pass From 6339a06b71f3daf035a3e9b49d1bc382550d4ad2 Mon Sep 17 00:00:00 2001 From: tonyrewin Date: Tue, 17 Jan 2023 09:20:09 +0300 Subject: [PATCH 5/6] fix --- migration/tables/remarks.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/migration/tables/remarks.py b/migration/tables/remarks.py index 1b6b6350..247d183f 100644 --- a/migration/tables/remarks.py +++ b/migration/tables/remarks.py @@ -5,8 +5,6 @@ from orm.remark import Remark def migrate(entry): - print(entry) - break remark = { "slug": entry["slug"], "oid": entry["_id"], @@ -20,7 +18,7 @@ def migrate(entry): with local_session() as session: slug = remark["slug"] rmrk = session.query(Remark).filter(Remark.slug == slug).first() or Remark.create( - **tooltip + **remark ) if not rmrk: raise Exception("no rmrk!") From b966ce6c2472a982ce793ef251ce0b718b97e12c Mon Sep 17 00:00:00 2001 From: tonyrewin Date: Tue, 17 Jan 2023 12:11:18 +0300 Subject: [PATCH 6/6] [api] remarks & drafts/collabs + migrations --- migration/__init__.py | 7 ++++--- migration/tables/remarks.py | 41 +++++++++++++++++++------------------ orm/remark.py | 4 ++-- resolvers/create/collab.py | 2 +- resolvers/zine/profile.py | 13 ++++++------ resolvers/zine/reactions.py | 3 +-- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/migration/__init__.py b/migration/__init__.py index 0737f6c5..c59e3ec4 100644 --- a/migration/__init__.py +++ b/migration/__init__.py @@ -140,7 +140,7 @@ async def remarks_handle(storage): print("[migration] comments") c = 0 for entry_remark in storage["remarks"]["data"]: - remark = await migrateRemark(entry_remark) + remark = await migrateRemark(entry_remark, storage) c += 1 print("[migration] " + str(c) + " remarks migrated") @@ -179,9 +179,9 @@ async def all_handle(storage, args): await users_handle(storage) await topics_handle(storage) print("[migration] users and topics are migrated") - await remarks_handle(storage) - print("[migration] remarks are migrated") await shouts_handle(storage, args) + print("[migration] remarks...") + await remarks_handle(storage) print("[migration] migrating comments") await comments_handle(storage) # export_email_subscriptions() @@ -202,6 +202,7 @@ def data_load(): "cats": [], "tags": [], }, + "remarks": {"data": []}, "users": {"by_oid": {}, "by_slug": {}, "data": []}, "replacements": json.loads(open("migration/tables/replacements.json").read()), } diff --git a/migration/tables/remarks.py b/migration/tables/remarks.py index 247d183f..78f52c92 100644 --- a/migration/tables/remarks.py +++ b/migration/tables/remarks.py @@ -4,27 +4,28 @@ from migration.html2text import html2text from orm.remark import Remark -def migrate(entry): +def migrate(entry, storage): + post_oid = entry['contentItem'] + print(post_oid) + shout_dict = storage['shouts']['by_oid'].get(post_oid) remark = { - "slug": entry["slug"], - "oid": entry["_id"], - "body": extract_md(html2text( - entry['body'] + entry['textAfter'] or '' + \ - entry['textBefore'] or '' + \ - entry['textSelected'] or '' - ), entry["_id"]) + "shout": shout_dict['id'], + "body": extract_md( + html2text(entry['body']), + entry['_id'] + ), + "desc": extract_md( + html2text( + entry['textAfter'] or '' + \ + entry['textBefore'] or '' + \ + entry['textSelected'] or '' + ), + entry["_id"] + ) } with local_session() as session: - slug = remark["slug"] - rmrk = session.query(Remark).filter(Remark.slug == slug).first() or Remark.create( - **remark - ) - if not rmrk: - raise Exception("no rmrk!") - if rmrk: - Remark.update(rmrk, remark) - session.commit() - rt = tt.__dict__.copy() - del rt["_sa_instance_state"] - return rt + rmrk = Remark.create(**remark) + session.commit() + del rmrk["_sa_instance_state"] + return rmrk diff --git a/orm/remark.py b/orm/remark.py index 89a6494a..9432a3f5 100644 --- a/orm/remark.py +++ b/orm/remark.py @@ -8,8 +8,8 @@ from base.orm import Base class Remark(Base): - tablename = "remark" + __tablename__ = "remark" - slug = Column(String, unique=True, nullable=False) body = Column(String, nullable=False) + desc = Column(String, default='') shout = Column(ForeignKey("shout.id"), nullable=True, index=True, comment="Shout") diff --git a/resolvers/create/collab.py b/resolvers/create/collab.py index 3fe4a169..f8b1c8a7 100644 --- a/resolvers/create/collab.py +++ b/resolvers/create/collab.py @@ -72,7 +72,7 @@ async def update_draft(_, info, draft_input): } else: draft_input["updatedAt"] = datetime.now(tz=timezone.utc) - collab.update(**draft_input) + collab.update(draft_input) session.commit() # TODO: email notify diff --git a/resolvers/zine/profile.py b/resolvers/zine/profile.py index 8cd68453..c70106df 100644 --- a/resolvers/zine/profile.py +++ b/resolvers/zine/profile.py @@ -162,16 +162,15 @@ async def update_profile(_, info, profile): user_id = auth.user_id with local_session() as session: user = session.query(User).filter(User.id == user_id).one() - slugowner = session.query(User).where(User.slug == profile['slug']).one() - if slugowner: - if slugowner.id != user_id: - return { - "error": "slug is used by another user" - } + if not user: + return { + "error": "canoot find user" + } user.update(profile) session.commit() return { - "error": None + "error": None, + "author": user } diff --git a/resolvers/zine/reactions.py b/resolvers/zine/reactions.py index 40c912a5..56bcafca 100644 --- a/resolvers/zine/reactions.py +++ b/resolvers/zine/reactions.py @@ -198,11 +198,10 @@ async def delete_reaction(_, info, reaction=None): auth: AuthCredentials = info.context["request"].auth with local_session() as session: - user = session.query(User).where(User.id == auth.user_id).first() r = session.query(Reaction).filter(Reaction.id == reaction).first() if not r: return {"error": "invalid reaction id"} - if r.createdBy != user.id: + if r.createdBy != auth.user_id: return {"error": "access denied"} r.deletedAt = datetime.now(tz=timezone.utc) session.commit()