From e286cf86613adfe091d024d080ef2644e05f8dfe Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 10 Apr 2022 20:19:40 +0100
Subject: [PATCH 1/4] Unit test for content diff
---
content.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests.py | 15 +++++++++++++++
2 files changed, 65 insertions(+)
diff --git a/content.py b/content.py
index 5bd414974..4a4f2990d 100644
--- a/content.py
+++ b/content.py
@@ -7,6 +7,7 @@ __email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "Core"
+import difflib
import math
import html
import os
@@ -1415,3 +1416,52 @@ def import_emoji(base_dir: str, import_filename: str, session) -> None:
added += 1
save_json(emoji_dict, base_dir + '/emoji/default_emoji.json')
print(str(added) + ' custom emoji added')
+
+
+def content_diff(content: str, prev_content: str) -> str:
+ """Returns a diff for the given content
+ """
+ d = difflib.Differ()
+ text1_lines = content.splitlines()
+ text2_lines = prev_content.splitlines()
+ diff = d.compare(text1_lines, text2_lines)
+
+ diff_content = content
+ diff_text = ''
+ reference_text = ''
+ change_positions = ''
+ for line in diff:
+ if line.startswith('- '):
+ reference_text = line[2:]
+ elif line.startswith('? '):
+ change_positions = line[2:]
+ state = 0
+ ctr = 0
+ for changed_char in change_positions:
+ if state == 0:
+ if changed_char == '-':
+ diff_text += \
+ '' + reference_text[ctr]
+ ctr += 1
+ state = 1
+ continue
+ elif changed_char == '+':
+ diff_text += \
+ '' + reference_text[ctr]
+ ctr += 1
+ state = 1
+ continue
+ elif state == 1:
+ if changed_char != '-' and changed_char != '+':
+ diff_text += ' ' + reference_text[ctr]
+ ctr += 1
+ state = 0
+ continue
+ diff_text += reference_text[ctr]
+ ctr += 1
+
+ while ctr < len(reference_text):
+ diff_text += reference_text[ctr]
+ ctr += 1
+ diff_content = diff_content.replace(reference_text, diff_text)
+ return diff_content
diff --git a/tests.py b/tests.py
index ec64f752e..2bc945046 100644
--- a/tests.py
+++ b/tests.py
@@ -129,6 +129,7 @@ from inbox import json_post_allows_comments
from inbox import valid_inbox
from inbox import valid_inbox_filenames
from categories import guess_hashtag_category
+from content import content_diff
from content import bold_reading_string
from content import safe_web_text
from content import words_similarity
@@ -6917,6 +6918,19 @@ def _test_bold_reading() -> None:
assert text_bold == expected
+def _test_diff_content() -> None:
+ print('diff_content')
+ prev_content = \
+ 'Some text before.\nThis is some content.\nThis is another line.'
+ content = \
+ 'Some text before.\nThis is some more content.\nThis is another line.'
+ result = content_diff(content, prev_content)
+ expected = 'Some text before.\n' + \
+ 'This is some ' + \
+ 'more content.\nThis is another line.'
+ assert result == expected
+
+
def run_all_tests():
base_dir = os.getcwd()
print('Running tests...')
@@ -6934,6 +6948,7 @@ def run_all_tests():
_test_checkbox_names()
_test_thread_functions()
_test_functions()
+ _test_diff_content()
_test_bold_reading()
_test_published_to_local_timezone()
_test_safe_webtext()
From c4fbdda58d88140fa9f3104ddc5304a54522b8e9 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 10 Apr 2022 23:50:44 +0100
Subject: [PATCH 2/4] Function to show edits to a post
---
content.py | 50 ++++++++++++++++++++++++++++++++++++++++++++
epicyon-profile.css | 10 +++++++++
translations/ar.json | 3 ++-
translations/ca.json | 3 ++-
translations/cy.json | 3 ++-
translations/de.json | 3 ++-
translations/en.json | 3 ++-
translations/es.json | 3 ++-
translations/fr.json | 3 ++-
translations/ga.json | 3 ++-
translations/hi.json | 3 ++-
translations/it.json | 3 ++-
translations/ja.json | 3 ++-
translations/ko.json | 3 ++-
translations/ku.json | 3 ++-
translations/oc.json | 3 ++-
translations/pl.json | 3 ++-
translations/pt.json | 3 ++-
translations/ru.json | 3 ++-
translations/sw.json | 3 ++-
translations/uk.json | 3 ++-
translations/zh.json | 3 ++-
webapp_post.py | 15 +++++++++++++
23 files changed, 115 insertions(+), 20 deletions(-)
diff --git a/content.py b/content.py
index 4a4f2990d..81c85631f 100644
--- a/content.py
+++ b/content.py
@@ -14,6 +14,9 @@ import os
import email.parser
import urllib.parse
from shutil import copyfile
+from dateutil.parser import parse
+from utils import convert_published_to_local_timezone
+from utils import has_object_dict
from utils import valid_hash_tag
from utils import dangerous_svg
from utils import remove_domain_port
@@ -1460,8 +1463,55 @@ def content_diff(content: str, prev_content: str) -> str:
diff_text += reference_text[ctr]
ctr += 1
+ if state == 1:
+ diff_text += ' '
+
while ctr < len(reference_text):
diff_text += reference_text[ctr]
ctr += 1
diff_content = diff_content.replace(reference_text, diff_text)
return diff_content
+
+
+def create_edits_html(edits_json: {}, post_json_object: {},
+ translate: {}, timezone: str) -> str:
+ """ Creates html showing historical edits made to a post
+ """
+ if not edits_json:
+ return ''
+ if not has_object_dict(post_json_object):
+ return ''
+ if not post_json_object['object'].get('content'):
+ return ''
+ edit_dates_list = []
+ for modified, item in edits_json.items():
+ edit_dates_list.append(modified)
+ edit_dates_list.sort(reverse=True)
+ edits_str = ''
+ content = remove_html(post_json_object['object']['content'])
+ for modified in edit_dates_list:
+ prev_json = edits_json[modified]
+ if not has_object_dict(prev_json):
+ continue
+ if not prev_json['object'].get('content'):
+ continue
+ prev_content = remove_html(prev_json['object']['content'])
+ if content == prev_content:
+ continue
+ diff = content_diff(content, prev_content)
+ if not diff:
+ continue
+ diff = diff.replace('\n', '
')
+ # convert to local time
+ datetime_object = parse(modified)
+ datetime_object = \
+ convert_published_to_local_timezone(datetime_object, timezone)
+ modified_str = datetime_object.strftime("%a %b %d, %H:%M")
+ diff = '
' + modified_str + '
' + diff + '
'
+ edits_str += diff
+ content = prev_content
+ if not edits_str:
+ return ''
+ return '' + \
+ translate['SHOW EDITS'] + ' ' + \
+ edits_str + ' \n'
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 6c44a8101..4062d2729 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -262,6 +262,16 @@ mark {
font-weight: bold;
}
+.diff_add {
+ color: var(--main-link-color);
+ text-decoration: underline;
+}
+
+.diff_remove {
+ color: var(--title-color);
+ text-decoration: underline;
+}
+
.accesskeys {
border: 0;
width: 100%;
diff --git a/translations/ar.json b/translations/ar.json
index 6f6f4ce23..e37a219e9 100644
--- a/translations/ar.json
+++ b/translations/ar.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "مسموح روبوتات الويب",
"Known Search Bots": "روبوتات بحث الويب المعروفة",
"mitm": "يمكن قراءة الرسالة أو تعديلها من قبل طرف ثالث",
- "Bold reading": "قراءة جريئة"
+ "Bold reading": "قراءة جريئة",
+ "SHOW EDITS": "عرض التعديلات"
}
diff --git a/translations/ca.json b/translations/ca.json
index 86651c8ae..543178e8a 100644
--- a/translations/ca.json
+++ b/translations/ca.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Bots web permesos",
"Known Search Bots": "Bots de cerca web coneguts",
"mitm": "El missatge podria haver estat llegit o modificat per un tercer",
- "Bold reading": "Lectura atrevida"
+ "Bold reading": "Lectura atrevida",
+ "SHOW EDITS": "MOSTRA EDICIONS"
}
diff --git a/translations/cy.json b/translations/cy.json
index 8bc01bdec..6ee8d7df8 100644
--- a/translations/cy.json
+++ b/translations/cy.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Web Bots a Ganiateir",
"Known Search Bots": "Bots Chwilio Gwe Hysbys",
"mitm": "Gallai'r neges fod wedi cael ei darllen neu ei haddasu gan drydydd parti",
- "Bold reading": "Darllen beiddgar"
+ "Bold reading": "Darllen beiddgar",
+ "SHOW EDITS": "GOLYGIADAU SIOE"
}
diff --git a/translations/de.json b/translations/de.json
index c2fe3ff2d..93037f42a 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Webbots erlaubt",
"Known Search Bots": "Bekannte Bots für die Websuche",
"mitm": "Die Nachricht könnte von einem Dritten gelesen oder geändert worden sein",
- "Bold reading": "Mutige Lektüre"
+ "Bold reading": "Mutige Lektüre",
+ "SHOW EDITS": "BEARBEITUNGEN ZEIGEN"
}
diff --git a/translations/en.json b/translations/en.json
index d70f59477..024f4573f 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Web Search Bots Allowed",
"Known Search Bots": "Known Web Search Bots",
"mitm": "Message could have been read or modified by a third party",
- "Bold reading": "Bold reading"
+ "Bold reading": "Bold reading",
+ "SHOW EDITS": "SHOW EDITS"
}
diff --git a/translations/es.json b/translations/es.json
index 3c3673ee3..b009522af 100644
--- a/translations/es.json
+++ b/translations/es.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Bots web permitidos",
"Known Search Bots": "Bots de búsqueda web conocidos",
"mitm": "El mensaje podría haber sido leído o modificado por un tercero",
- "Bold reading": "Lectura en negrita"
+ "Bold reading": "Lectura en negrita",
+ "SHOW EDITS": "MOSTRAR EDICIONES"
}
diff --git a/translations/fr.json b/translations/fr.json
index a553b49b8..f932bd705 100644
--- a/translations/fr.json
+++ b/translations/fr.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Robots Web autorisés",
"Known Search Bots": "Robots de recherche Web connus",
"mitm": "Le message a pu être lu ou modifié par un tiers",
- "Bold reading": "Lecture audacieuse"
+ "Bold reading": "Lecture audacieuse",
+ "SHOW EDITS": "AFFICHER LES MODIFICATIONS"
}
diff --git a/translations/ga.json b/translations/ga.json
index c1f065901..a5c8836cb 100644
--- a/translations/ga.json
+++ b/translations/ga.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Róbónna Gréasáin Ceadaithe",
"Known Search Bots": "Róbónna Cuardach Gréasáin Aitheanta",
"mitm": "D'fhéadfadh tríú páirtí an teachtaireacht a léamh nó a mhodhnú",
- "Bold reading": "Léamh trom"
+ "Bold reading": "Léamh trom",
+ "SHOW EDITS": "EAGARTHÓIRÍ TAISPEÁINT"
}
diff --git a/translations/hi.json b/translations/hi.json
index 6845d4d27..f97bfe869 100644
--- a/translations/hi.json
+++ b/translations/hi.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "वेब बॉट्स की अनुमति है",
"Known Search Bots": "ज्ञात वेब खोज बॉट्स",
"mitm": "संदेश किसी तीसरे पक्ष द्वारा पढ़ा या संशोधित किया जा सकता था",
- "Bold reading": "बोल्ड रीडिंग"
+ "Bold reading": "बोल्ड रीडिंग",
+ "SHOW EDITS": "संपादन दिखाएं"
}
diff --git a/translations/it.json b/translations/it.json
index d6bd3418f..2e47edd74 100644
--- a/translations/it.json
+++ b/translations/it.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Web bot consentiti",
"Known Search Bots": "Bot di ricerca Web noti",
"mitm": "Il messaggio potrebbe essere stato letto o modificato da terzi",
- "Bold reading": "Lettura audace"
+ "Bold reading": "Lettura audace",
+ "SHOW EDITS": "MOSTRA MODIFICHE"
}
diff --git a/translations/ja.json b/translations/ja.json
index 0d6fe2b7e..a4e390b59 100644
--- a/translations/ja.json
+++ b/translations/ja.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "許可されたWebボット",
"Known Search Bots": "既知のWeb検索ボット",
"mitm": "メッセージが第三者によって読み取られたり変更されたりした可能性があります",
- "Bold reading": "大胆な読書"
+ "Bold reading": "大胆な読書",
+ "SHOW EDITS": "編集を表示"
}
diff --git a/translations/ko.json b/translations/ko.json
index 96b6e038a..e32e293a1 100644
--- a/translations/ko.json
+++ b/translations/ko.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "웹 봇 허용",
"Known Search Bots": "알려진 웹 검색 봇",
"mitm": "제3자가 메시지를 읽거나 수정했을 수 있습니다.",
- "Bold reading": "굵은 글씨"
+ "Bold reading": "굵은 글씨",
+ "SHOW EDITS": "수정사항 보기"
}
diff --git a/translations/ku.json b/translations/ku.json
index 2aa459238..54ecfdca6 100644
--- a/translations/ku.json
+++ b/translations/ku.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Web Bots Destûrdar in",
"Known Search Bots": "Botên Lêgerîna Webê yên naskirî",
"mitm": "Peyam dikaribû ji hêla aliyek sêyemîn ve were xwendin an guhertin",
- "Bold reading": "Xwendina qelew"
+ "Bold reading": "Xwendina qelew",
+ "SHOW EDITS": "GERÎŞTAN NÎŞAN DE"
}
diff --git a/translations/oc.json b/translations/oc.json
index c6e69765c..0715ea292 100644
--- a/translations/oc.json
+++ b/translations/oc.json
@@ -515,5 +515,6 @@
"Web Bots Allowed": "Web Search Bots Allowed",
"Known Search Bots": "Known Web Search Bots",
"mitm": "Message could have been read or modified by a third party",
- "Bold reading": "Bold reading"
+ "Bold reading": "Bold reading",
+ "SHOW EDITS": "SHOW EDITS"
}
diff --git a/translations/pl.json b/translations/pl.json
index fb6e675b1..76d0279fd 100644
--- a/translations/pl.json
+++ b/translations/pl.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Dozwolone boty internetowe",
"Known Search Bots": "Znane boty wyszukiwania w sieci",
"mitm": "Wiadomość mogła zostać przeczytana lub zmodyfikowana przez osobę trzecią",
- "Bold reading": "Odważne czytanie"
+ "Bold reading": "Odważne czytanie",
+ "SHOW EDITS": "POKAŻ EDYCJE"
}
diff --git a/translations/pt.json b/translations/pt.json
index 98a6db584..dfca1a257 100644
--- a/translations/pt.json
+++ b/translations/pt.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Webbots permitidos",
"Known Search Bots": "Bots de pesquisa na Web conhecidos",
"mitm": "A mensagem pode ter sido lida ou modificada por terceiros",
- "Bold reading": "Leitura em negrito"
+ "Bold reading": "Leitura em negrito",
+ "SHOW EDITS": "MOSTRAR EDIÇÕES"
}
diff --git a/translations/ru.json b/translations/ru.json
index e8d906959..697040b14 100644
--- a/translations/ru.json
+++ b/translations/ru.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Веб-боты разрешены",
"Known Search Bots": "Известные боты веб-поиска",
"mitm": "Сообщение могло быть прочитано или изменено третьим лицом",
- "Bold reading": "Смелое чтение"
+ "Bold reading": "Смелое чтение",
+ "SHOW EDITS": "ПОКАЗАТЬ РЕДАКТИРОВАНИЕ"
}
diff --git a/translations/sw.json b/translations/sw.json
index 39e466044..f2666243e 100644
--- a/translations/sw.json
+++ b/translations/sw.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Mtandao wa Boti Unaruhusiwa",
"Known Search Bots": "Vijibu vya Utafutaji wa Wavuti vinavyojulikana",
"mitm": "Ujumbe ungeweza kusomwa au kurekebishwa na mtu mwingine",
- "Bold reading": "Kusoma kwa ujasiri"
+ "Bold reading": "Kusoma kwa ujasiri",
+ "SHOW EDITS": "ONYESHA MABADILIKO"
}
diff --git a/translations/uk.json b/translations/uk.json
index 009245795..081e7ba6d 100644
--- a/translations/uk.json
+++ b/translations/uk.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "Веб-боти дозволені",
"Known Search Bots": "Відомі пошукові роботи в Інтернеті",
"mitm": "Повідомлення могло бути прочитане або змінене третьою стороною",
- "Bold reading": "Сміливе читання"
+ "Bold reading": "Сміливе читання",
+ "SHOW EDITS": "ПОКАЗАТИ ЗМІНИ"
}
diff --git a/translations/zh.json b/translations/zh.json
index c9624fce1..114885e74 100644
--- a/translations/zh.json
+++ b/translations/zh.json
@@ -519,5 +519,6 @@
"Web Bots Allowed": "允许网络机器人",
"Known Search Bots": "已知的网络搜索机器人",
"mitm": "消息可能已被第三方阅读或修改",
- "Bold reading": "大胆阅读"
+ "Bold reading": "大胆阅读",
+ "SHOW EDITS": "显示编辑"
}
diff --git a/webapp_post.py b/webapp_post.py
index 61fbf0fae..448a73f85 100644
--- a/webapp_post.py
+++ b/webapp_post.py
@@ -58,6 +58,7 @@ from utils import get_domain_from_actor
from utils import acct_dir
from utils import local_actor_url
from utils import is_unlisted_post
+from content import create_edits_html
from content import bold_reading_string
from content import limit_repeated_words
from content import replace_emoji_from_tags
@@ -1479,6 +1480,18 @@ def individual_post_as_html(signing_priv_key_pem: str,
_log_post_timing(enable_timing_log, post_start_time, '2')
+ # does this post have edits?
+ edits_post_url = \
+ remove_id_ending(message_id.strip()).replace('/', '#') + '.edits'
+ account_dir = acct_dir(base_dir, nickname, domain) + '/'
+ edits_filename = account_dir + box_name + '/' + edits_post_url
+ edits_str = ''
+ if os.path.isfile(edits_filename):
+ edits_json = load_json(edits_filename, 0, 1)
+ if edits_json:
+ edits_str = create_edits_html(edits_json, post_json_object,
+ translate, timezone)
+
message_id_str = ''
if message_id:
message_id_str = ';' + message_id
@@ -2016,6 +2029,8 @@ def individual_post_as_html(signing_priv_key_pem: str,
if not is_pgp_encrypted(content_str):
if not is_patch:
+ # append any edits
+ content_str += edits_str
# Add bold text
if bold_reading and \
not displaying_ciphertext and \
From 8f6980ccabd7fa82f6cc9fa57f5daf83abf33afd Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 11 Apr 2022 10:59:35 +0100
Subject: [PATCH 3/4] Update edits file for delete-and-redraft edits
---
inbox.py | 63 ++++++++++++++++++++++++++++++++++++++++++--------------
posts.py | 54 ++++++++++++++++++++++++------------------------
2 files changed, 75 insertions(+), 42 deletions(-)
diff --git a/inbox.py b/inbox.py
index 8fc5b911e..bdf6f32b1 100644
--- a/inbox.py
+++ b/inbox.py
@@ -12,6 +12,7 @@ import os
import datetime
import time
import random
+from shutil import copyfile
from linked_data_sig import verify_json_signature
from languages import understood_post_language
from like import update_likes_collection
@@ -1064,8 +1065,9 @@ def _receive_edit_to_post(recent_posts_cache: {}, message_json: {},
published_str = post_json_object['object']['updated']
else:
published_str = post_json_object['object']['published']
- post_history_json[published_str] = post_json_object
- save_json(post_history_json, post_history_filename)
+ if not post_history_json.get(published_str):
+ post_history_json[published_str] = post_json_object
+ save_json(post_history_json, post_history_filename)
# Change Update to Create
message_json['type'] = 'Create'
save_json(message_json, post_filename)
@@ -3930,6 +3932,50 @@ def _inbox_after_initial(server,
except OSError:
print('EX: unable to write ' + destination_filename_muted)
+ # is this an edit of a previous post?
+ # in Mastodon "delete and redraft"
+ # NOTE: this must be done before update_conversation is called
+ edited_filename, edited_json = \
+ edited_post_filename(base_dir, handle_name, domain,
+ post_json_object, debug, 300)
+
+ # If this was an edit then update the edits json file and
+ # delete the previous version of the post
+ if edited_filename and edited_json:
+ prev_edits_filename = \
+ edited_filename.replace('.json', '.edits')
+ edits_filename = \
+ destination_filename.replace('.json', '.edits')
+ modified = edited_json['object']['published']
+ if os.path.isfile(edits_filename):
+ edits_json = load_json(edits_filename)
+ if edits_json:
+ if not edits_json.get(modified):
+ edits_json[modified] = edited_json
+ save_json(edits_json, edits_filename)
+ else:
+ if os.path.isfile(prev_edits_filename):
+ if prev_edits_filename != edits_filename:
+ try:
+ copyfile(prev_edits_filename, edits_filename)
+ except OSError:
+ print('EX: failed to copy edits file')
+ edits_json = load_json(edits_filename)
+ if edits_json:
+ if not edits_json.get(modified):
+ edits_json[modified] = edited_json
+ save_json(edits_json, edits_filename)
+ else:
+ edits_json = {
+ modified: edited_json
+ }
+ save_json(edits_json, edits_filename)
+
+ if edited_filename != destination_filename:
+ delete_post(base_dir, http_prefix,
+ nickname, domain, edited_filename,
+ debug, recent_posts_cache)
+
# update the indexes for different timelines
for boxname in update_index_list:
if not inbox_update_index(boxname, base_dir, handle,
@@ -3983,22 +4029,9 @@ def _inbox_after_initial(server,
boxname + ' post as html to cache in ' +
time_diff + ' mS')
- # is this an edit of a previous post?
- # in Mastodon "delete and redraft"
- # NOTE: this must be done before update_conversation is called
- edited_filename = \
- edited_post_filename(base_dir, handle_name, domain,
- post_json_object, debug, 300)
-
update_conversation(base_dir, handle_name, domain,
post_json_object)
- # If this was an edit then delete the previous version of the post
- if edited_filename:
- delete_post(base_dir, http_prefix,
- nickname, domain, edited_filename,
- debug, recent_posts_cache)
-
# store the id of the last post made by this actor
_store_last_post_id(base_dir, nickname, domain, post_json_object)
diff --git a/posts.py b/posts.py
index 45f2a12f8..0a2be1f95 100644
--- a/posts.py
+++ b/posts.py
@@ -5476,31 +5476,31 @@ def seconds_between_published(published1: str, published2: str) -> int:
def edited_post_filename(base_dir: str, nickname: str, domain: str,
post_json_object: {}, debug: bool,
- max_time_diff_seconds: int) -> str:
+ max_time_diff_seconds: int) -> (str, {}):
"""Returns the filename of the edited post
"""
if not has_object_dict(post_json_object):
- return ''
+ return '', None
if not post_json_object.get('type'):
- return ''
+ return '', None
if not post_json_object['object'].get('type'):
- return ''
+ return '', None
if not post_json_object['object'].get('published'):
- return ''
+ return '', None
if not post_json_object['object'].get('id'):
- return ''
+ return '', None
if not post_json_object['object'].get('content'):
- return ''
+ return '', None
if not post_json_object['object'].get('attributedTo'):
- return ''
+ return '', None
if not isinstance(post_json_object['object']['attributedTo'], str):
- return ''
+ return '', None
actor = post_json_object['object']['attributedTo']
actor_filename = \
acct_dir(base_dir, nickname, domain) + '/lastpost/' + \
actor.replace('/', '#')
if not os.path.isfile(actor_filename):
- return ''
+ return '', None
post_id = remove_id_ending(post_json_object['object']['id'])
lastpost_id = None
try:
@@ -5508,48 +5508,48 @@ def edited_post_filename(base_dir: str, nickname: str, domain: str,
lastpost_id = fp_actor.read()
except OSError:
print('EX: edited_post_filename unable to read ' + actor_filename)
- return ''
+ return '', None
if not lastpost_id:
- return ''
+ return '', None
if lastpost_id == post_id:
- return ''
+ return '', None
lastpost_filename = \
locate_post(base_dir, nickname, domain, lastpost_id, False)
if not lastpost_filename:
- return ''
+ return '', None
lastpost_json = load_json(lastpost_filename, 0)
if not lastpost_json:
- return ''
+ return '', None
if not lastpost_json.get('type'):
- return ''
+ return '', None
if lastpost_json['type'] != post_json_object['type']:
- return ''
+ return '', None
if not lastpost_json['object'].get('type'):
- return ''
+ return '', None
if lastpost_json['object']['type'] != post_json_object['object']['type']:
- return
+ return '', None
if not lastpost_json['object'].get('published'):
- return ''
+ return '', None
if not lastpost_json['object'].get('id'):
- return ''
+ return '', None
if not lastpost_json['object'].get('content'):
- return ''
+ return '', None
if not lastpost_json['object'].get('attributedTo'):
- return ''
+ return '', None
if not isinstance(lastpost_json['object']['attributedTo'], str):
- return ''
+ return '', None
time_diff_seconds = \
seconds_between_published(lastpost_json['object']['published'],
post_json_object['object']['published'])
if time_diff_seconds > max_time_diff_seconds:
- return ''
+ return '', None
if debug:
print(post_id + ' might be an edit of ' + lastpost_id)
if words_similarity(lastpost_json['object']['content'],
post_json_object['object']['content'], 10) < 70:
- return ''
+ return '', None
print(post_id + ' is an edit of ' + lastpost_id)
- return lastpost_filename
+ return lastpost_filename, lastpost_json
def get_original_post_from_announce_url(announce_url: str, base_dir: str,
From d7bb5dc1c7b40cef1f1737d39f8498b8dc14d590 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 11 Apr 2022 13:13:04 +0100
Subject: [PATCH 4/4] Fixing edit diffs
---
content.py | 74 +++++++++++++++++++++++-------------------------------
daemon.py | 2 +-
tests.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 100 insertions(+), 48 deletions(-)
diff --git a/content.py b/content.py
index 81c85631f..be1a07503 100644
--- a/content.py
+++ b/content.py
@@ -1426,51 +1426,39 @@ def content_diff(content: str, prev_content: str) -> str:
"""
d = difflib.Differ()
text1_lines = content.splitlines()
- text2_lines = prev_content.splitlines()
- diff = d.compare(text1_lines, text2_lines)
+ text1_sentences = []
+ for line in text1_lines:
+ sentences = line.split('.')
+ for sentence in sentences:
+ text1_sentences.append(sentence.strip())
+
+ text2_lines = prev_content.splitlines()
+ text2_sentences = []
+ for line in text2_lines:
+ sentences = line.split('.')
+ for sentence in sentences:
+ text2_sentences.append(sentence.strip())
+
+ diff = d.compare(text1_sentences, text2_sentences)
- diff_content = content
diff_text = ''
- reference_text = ''
- change_positions = ''
for line in diff:
if line.startswith('- '):
- reference_text = line[2:]
- elif line.startswith('? '):
- change_positions = line[2:]
- state = 0
- ctr = 0
- for changed_char in change_positions:
- if state == 0:
- if changed_char == '-':
- diff_text += \
- '' + reference_text[ctr]
- ctr += 1
- state = 1
- continue
- elif changed_char == '+':
- diff_text += \
- '' + reference_text[ctr]
- ctr += 1
- state = 1
- continue
- elif state == 1:
- if changed_char != '-' and changed_char != '+':
- diff_text += ' ' + reference_text[ctr]
- ctr += 1
- state = 0
- continue
- diff_text += reference_text[ctr]
- ctr += 1
-
- if state == 1:
- diff_text += ' '
-
- while ctr < len(reference_text):
- diff_text += reference_text[ctr]
- ctr += 1
- diff_content = diff_content.replace(reference_text, diff_text)
- return diff_content
+ if not diff_text:
+ diff_text = ''
+ else:
+ diff_text += ' '
+ diff_text += '+ ' + line[2:] + ' '
+ elif line.startswith('+ '):
+ if not diff_text:
+ diff_text = '
'
+ else:
+ diff_text += ' '
+ diff_text += \
+ '- ' + line[2:] + ' '
+ if diff_text:
+ diff_text += '
'
+ return diff_text
def create_edits_html(edits_json: {}, post_json_object: {},
@@ -1507,11 +1495,11 @@ def create_edits_html(edits_json: {}, post_json_object: {},
datetime_object = \
convert_published_to_local_timezone(datetime_object, timezone)
modified_str = datetime_object.strftime("%a %b %d, %H:%M")
- diff = '' + modified_str + '
' + diff + '
'
+ diff = '' + modified_str + '
' + diff
edits_str += diff
content = prev_content
if not edits_str:
return ''
return '' + \
translate['SHOW EDITS'] + ' ' + \
- edits_str + ' \n'
+ edits_str + ''
diff --git a/daemon.py b/daemon.py
index 3246da238..c9a4aa6f8 100644
--- a/daemon.py
+++ b/daemon.py
@@ -20792,7 +20792,7 @@ def run_daemon(check_actor_timeout: int,
check_actor_timeout = 2
httpd.check_actor_timeout = check_actor_timeout
- # how many hours after a post was publushed can a reply be made
+ # how many hours after a post was published can a reply be made
default_reply_interval_hrs = 9999999
httpd.default_reply_interval_hrs = default_reply_interval_hrs
diff --git a/tests.py b/tests.py
index 2bc945046..6eacaa61f 100644
--- a/tests.py
+++ b/tests.py
@@ -129,6 +129,7 @@ from inbox import json_post_allows_comments
from inbox import valid_inbox
from inbox import valid_inbox_filenames
from categories import guess_hashtag_category
+from content import create_edits_html
from content import content_diff
from content import bold_reading_string
from content import safe_web_text
@@ -6921,15 +6922,78 @@ def _test_bold_reading() -> None:
def _test_diff_content() -> None:
print('diff_content')
prev_content = \
- 'Some text before.\nThis is some content.\nThis is another line.'
+ 'Some text before.\n' + \
+ 'Starting sentence. This is some content.\nThis is another line.'
content = \
'Some text before.\nThis is some more content.\nThis is another line.'
result = content_diff(content, prev_content)
- expected = 'Some text before.\n' + \
- 'This is some ' + \
- 'more content.\nThis is another line.'
+ expected = \
+ '' + \
+ '- Starting sentence ' + \
+ '+ This is some more content ' + \
+ '- This is some content
'
assert result == expected
+ content = \
+ 'Some text before.\nThis is content.\nThis line.'
+ result = content_diff(content, prev_content)
+ expected = \
+ '- Starting sentence ' + \
+ '+ This is content ' + \
+ '- This is some content ' + \
+ '+ This line ' + \
+ '- This is another line
'
+ assert result == expected
+
+ translate = {
+ "SHOW EDITS": "SHOW EDITS"
+ }
+ timezone = 'Europe/Berlin'
+ content1 = \
+ "This is some content.
" + \
+ "Some other content.
"
+ content2 = \
+ "This is some previous content.
" + \
+ "Some other previous content.
"
+ content3 = \
+ "This is some more previous content.
" + \
+ "Some other previous content.
"
+ post_json_object = {
+ "object": {
+ "content": content1,
+ "published": "2020-12-14T00:08:06Z"
+ }
+ }
+ edits_json = {
+ "2020-12-14T00:05:19Z": {
+ "object": {
+ "content": content3,
+ "published": "2020-12-14T00:05:19Z"
+ }
+ },
+ "2020-12-14T00:07:34Z": {
+ "object": {
+ "content": content2,
+ "published": "2020-12-14T00:07:34Z"
+ }
+ }
+ }
+ html_str = \
+ create_edits_html(edits_json, post_json_object, translate, timezone)
+ assert html_str
+ expected = \
+ 'SHOW EDITS ' + \
+ 'Mon Dec 14, 01:07
' + \
+ '+ This is some content ' + \
+ '- This is some previous content ' + \
+ '+ Some other content ' + \
+ '- Some other previous content' + \
+ '
Mon Dec 14, 01:05
' + \
+ '+ This is some previous content' + \
+ ' ' + \
+ '- This is some more previous content
'
+ assert html_str == expected
+
def run_all_tests():
base_dir = os.getcwd()