diff --git a/migration/extract.py b/migration/extract.py index 5dd7ccba..d67275a9 100644 --- a/migration/extract.py +++ b/migration/extract.py @@ -27,6 +27,39 @@ def replace_tooltips(body): return newbody + +def extract_footnotes(body, shout_dict): + parts = body.split("&&&") + lll = len(parts) + newparts = list(parts) + placed = False + if lll & 1: + if lll > 1: + i = 1 + print("[extract] found %d footnotes in body" % (lll - 1)) + for part in parts[1:]: + if i & 1: + placed = True + if 'a class="footnote-url" href=' in part: + print("[extract] footnote: " + part) + fn = 'a class="footnote-url" href="' + exxtracted_link = part.split(fn, 1)[1].split('"', 1)[0] + extracted_body = part.split(fn, 1)[1].split('>', 1)[1].split('', 1)[0] + print("[extract] footnote link: " + extracted_link) + with local_session() as session: + Reaction.create({ + "shout": shout_dict['id'], + "kind": ReactionKind.FOOTNOTE, + "body": extracted_body, + "range": str(body.index(fn + link) - len('<')) + ':' + str(body.index(extracted_body) + len('')) + }) + newparts[i] = "ℹ️" + else: + newparts[i] = part + i += 1 + return ("".join(newparts), placed) + + def place_tooltips(body): parts = body.split("&&&") lll = len(parts) @@ -203,7 +236,7 @@ def extract_dataimages(parts, prefix): di = "data:image" -def extract_md_images(body, oid): +def extract_md_images(body, prefix): newbody = "" body = ( body.replace("\n! [](" + di, "\n ![](" + di) @@ -212,7 +245,7 @@ def extract_md_images(body, oid): ) parts = body.split(di) if len(parts) > 1: - newbody = extract_dataimages(parts, oid) + newbody = extract_dataimages(parts, prefix) else: newbody = body return newbody @@ -238,24 +271,24 @@ def cleanup(body): return newbody -def extract_md(body, oid=""): +def extract_md(body, shout_dict = None): newbody = body if newbody: - uid = oid or uuid.uuid4() - newbody = extract_md_images(newbody, uid) - if not newbody: - raise Exception("extract_images error") - newbody = cleanup(newbody) if not newbody: raise Exception("cleanup error") - newbody, placed = place_tooltips(newbody) - if not newbody: - raise Exception("place_tooltips error") + if shout_dict: + + uid = shout_dict['id'] or uuid.uuid4() + newbody = extract_md_images(newbody, uid) + if not newbody: + raise Exception("extract_images error") + + newbody, placed = extract_footnotes(body, shout_dict) + if not newbody: + raise Exception("extract_footnotes error") - if placed: - newbody = "import Tooltip from '$/components/Article/Tooltip'\n\n" + newbody return newbody @@ -342,7 +375,9 @@ def prepare_html_body(entry): return body -def extract_html(entry): +def extract_html(entry, shout_id = None): body_orig = (entry.get("body") or "").replace('\(', '(').replace('\)', ')') + if shout_id: + extract_footnotes(body_orig, shout_id) body_html = str(BeautifulSoup(body_orig, features="html.parser")) return body_html diff --git a/migration/tables/remarks.py b/migration/tables/remarks.py index 78f52c92..026b95c6 100644 --- a/migration/tables/remarks.py +++ b/migration/tables/remarks.py @@ -1,31 +1,42 @@ from base.orm import local_session from migration.extract import extract_md from migration.html2text import html2text -from orm.remark import Remark +from orm.reaction import Reaction, ReactionKind def migrate(entry, storage): post_oid = entry['contentItem'] print(post_oid) shout_dict = storage['shouts']['by_oid'].get(post_oid) - remark = { - "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 '' + if shout_dict: + print(shout_dict['body']) + remark = { + "shout": shout_dict['id'], + "body": extract_md( + html2text(entry['body']), + shout_dict ), - entry["_id"] - ) - } + "kind": ReactionKind.REMARK + } - with local_session() as session: - rmrk = Remark.create(**remark) - session.commit() - del rmrk["_sa_instance_state"] - return rmrk + if entry.get('textBefore'): + remark['range'] = str( + shout_dict['body'] + .index( + entry['textBefore'] or '' + ) + ) + ':' + str( + shout_dict['body'] + .index( + entry['textAfter'] or '' + ) + len( + entry['textAfter'] or '' + ) + ) + + with local_session() as session: + rmrk = Reaction.create(**remark) + session.commit() + del rmrk["_sa_instance_state"] + return rmrk + return diff --git a/migration/tables/topics.py b/migration/tables/topics.py index 3287adb7..17804376 100644 --- a/migration/tables/topics.py +++ b/migration/tables/topics.py @@ -10,7 +10,7 @@ def migrate(entry): "slug": entry["slug"], "oid": entry["_id"], "title": entry["title"].replace(" ", " "), - "body": extract_md(html2text(body_orig), entry["_id"]) + "body": extract_md(html2text(body_orig)) } with local_session() as session: diff --git a/orm/reaction.py b/orm/reaction.py index f484808a..c2b43856 100644 --- a/orm/reaction.py +++ b/orm/reaction.py @@ -19,6 +19,8 @@ class ReactionKind(Enumeration): REJECT = 0 # -1 LIKE = 11 # +1 DISLIKE = 12 # -1 + REMARK = 13 + FOOTNOTE = 14 # TYPE = # rating diff diff --git a/orm/remark.py b/orm/remark.py deleted file mode 100644 index 9432a3f5..00000000 --- a/orm/remark.py +++ /dev/null @@ -1,15 +0,0 @@ -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" - - body = Column(String, nullable=False) - desc = Column(String, default='') - shout = Column(ForeignKey("shout.id"), nullable=True, index=True, comment="Shout") diff --git a/resolvers/zine/reactions.py b/resolvers/zine/reactions.py index 56bcafca..0aaa55cf 100644 --- a/resolvers/zine/reactions.py +++ b/resolvers/zine/reactions.py @@ -132,6 +132,23 @@ async def create_reaction(_, info, reaction={}): reaction['createdBy'] = auth.user_id with local_session() as session: r = Reaction.create(**reaction) + shout = session.query(Shout).where(Shout.id == r.shout).one() + + # Proposal accepting logix + if r.replyTo is not None and \ + r.kind == ReactionKind.ACCEPT and \ + user_id in shout.dict()['authors']: + replied_reaction = session.query(Reaction).when(Reaction.id == r.replyTo).first() + if replied_reaction and replied_reaction.kind == ReactionKind.PROPOSE: + if replied_reaction.range: + old_body = shout.body + start, end = replied_reaction.range.split(':') + start = int(start) + end = int(end) + new_body = old_body[:start] + replied_reaction.body + old_body[end:] + shout.body = new_body + # TODO: update git version control + session.add(r) session.commit() @@ -205,7 +222,9 @@ async def delete_reaction(_, info, reaction=None): return {"error": "access denied"} r.deletedAt = datetime.now(tz=timezone.utc) session.commit() - return {} + return { + "reaction": r + } @query.field("loadReactionsBy") diff --git a/resolvers/zine/remark.py b/resolvers/zine/remark.py deleted file mode 100644 index 6f5f9d48..00000000 --- a/resolvers/zine/remark.py +++ /dev/null @@ -1,48 +0,0 @@ - -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 diff --git a/schema.graphql b/schema.graphql index 080cb371..cf66d24d 100644 --- a/schema.graphql +++ b/schema.graphql @@ -407,6 +407,9 @@ enum ReactionKind { PROPOSE ASK + REMARK + FOOTNOTE + ACCEPT REJECT }