diff --git a/inbox.py b/inbox.py index 3e9bd1caa..89bae2036 100644 --- a/inbox.py +++ b/inbox.py @@ -1372,7 +1372,8 @@ def _receiveAnnounce(recentPostsCache: {}, messageJson, __version__, translate, YTReplacementDomain, - allowLocalNetworkAccess) + allowLocalNetworkAccess, + recentPostsCache) if not postJsonObject: notInOnion = True if onionDomain: @@ -2450,7 +2451,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, if isImageMedia(session, baseDir, httpPrefix, nickname, domain, postJsonObject, translate, YTReplacementDomain, - allowLocalNetworkAccess): + allowLocalNetworkAccess, + recentPostsCache): # media index will be updated updateIndexList.append('tlmedia') if isBlogPost(postJsonObject): diff --git a/newswire.py b/newswire.py index 29e24e3b7..d54bcfe22 100644 --- a/newswire.py +++ b/newswire.py @@ -148,7 +148,7 @@ def _validFeedDate(pubDate: str) -> bool: # convert from YY-MM-DD HH:MM:SS+00:00 to # YY-MM-DDTHH:MM:SSZ postDate = pubDate.replace(' ', 'T').replace('+00:00', 'Z') - return validPostDate(postDate, 30) + return validPostDate(postDate, 90) def parseFeedDate(pubDate: str) -> str: diff --git a/posts.py b/posts.py index ff00c98a1..dbf0dc2fe 100644 --- a/posts.py +++ b/posts.py @@ -31,6 +31,7 @@ from session import postImage from webfinger import webfingerHandle from httpsig import createSignedHeader from siteactive import siteIsActive +from utils import rejectPostId from utils import removeInvalidChars from utils import fileLastModified from utils import isPublicPost @@ -2952,7 +2953,8 @@ def isImageMedia(session, baseDir: str, httpPrefix: str, nickname: str, domain: str, postJsonObject: {}, translate: {}, YTReplacementDomain: str, - allowLocalNetworkAccess: bool) -> bool: + allowLocalNetworkAccess: bool, + recentPostsCache: {}) -> bool: """Returns true if the given post has attached image media """ if postJsonObject['type'] == 'Announce': @@ -2961,7 +2963,8 @@ def isImageMedia(session, baseDir: str, httpPrefix: str, nickname, domain, postJsonObject, __version__, translate, YTReplacementDomain, - allowLocalNetworkAccess) + allowLocalNetworkAccess, + recentPostsCache) if postJsonAnnounce: postJsonObject = postJsonAnnounce if postJsonObject['type'] != 'Create': @@ -3146,9 +3149,9 @@ def _createBoxIndexed(recentPostsCache: {}, '/' + indexBoxName + '.index' postsCtr = 0 if os.path.isfile(indexFilename): - maxPostCtr = itemsPerPage * pageNumber with open(indexFilename, 'r') as indexFile: - while postsCtr < maxPostCtr: + postsAddedToTimeline = 0 + while postsAddedToTimeline < itemsPerPage: postFilename = indexFile.readline() if not postFilename: @@ -3213,19 +3216,26 @@ def _createBoxIndexed(recentPostsCache: {}, if postUrl in recentPostsCache['index']: if recentPostsCache['json'].get(postUrl): url = recentPostsCache['json'][postUrl] - _addPostStringToTimeline(url, - boxname, postsInBox, - boxActor) - postsCtr += 1 - continue + if _addPostStringToTimeline(url, + boxname, postsInBox, + boxActor): + postsCtr += 1 + postsAddedToTimeline += 1 + continue # read the post from file fullPostFilename = \ locatePost(baseDir, nickname, domain, postUrl, False) if fullPostFilename: - _addPostToTimeline(fullPostFilename, boxname, - postsInBox, boxActor) + # has the post been rejected? + if os.path.isfile(fullPostFilename + '.reject'): + continue + + if _addPostToTimeline(fullPostFilename, boxname, + postsInBox, boxActor): + postsAddedToTimeline += 1 + postsCtr += 1 else: if timelineNickname != nickname: # if this is the features timeline @@ -3233,8 +3243,10 @@ def _createBoxIndexed(recentPostsCache: {}, locatePost(baseDir, timelineNickname, domain, postUrl, False) if fullPostFilename: - _addPostToTimeline(fullPostFilename, boxname, - postsInBox, boxActor) + if _addPostToTimeline(fullPostFilename, boxname, + postsInBox, boxActor): + postsAddedToTimeline += 1 + postsCtr += 1 else: print('WARN: features timeline. ' + 'Unable to locate post ' + postUrl) @@ -3242,7 +3254,9 @@ def _createBoxIndexed(recentPostsCache: {}, print('WARN: Unable to locate post ' + postUrl + ' nickname ' + nickname) - postsCtr += 1 + if postsCtr < 3: + print('Posts added to json timeline ' + boxname + ': ' + + str(postsAddedToTimeline)) # Generate first and last entries within header if postsCtr > 0: @@ -3865,9 +3879,14 @@ def populateRepliesJson(baseDir: str, nickname: str, domain: str, repliesJson['orderedItems'].append(pjo) -def _rejectAnnounce(announceFilename: str): +def _rejectAnnounce(announceFilename: str, + baseDir: str, nickname: str, domain: str, + announcePostId: str, recentPostsCache: {}): """Marks an announce as rejected """ + rejectPostId(baseDir, nickname, domain, announcePostId, recentPostsCache) + + # reject the post referenced by the announce activity object if not os.path.isfile(announceFilename + '.reject'): rejectAnnounceFile = open(announceFilename + '.reject', "w+") if rejectAnnounceFile: @@ -3879,7 +3898,8 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str, nickname: str, domain: str, postJsonObject: {}, projectVersion: str, translate: {}, YTReplacementDomain: str, - allowLocalNetworkAccess: bool) -> {}: + allowLocalNetworkAccess: bool, + recentPostsCache: {}) -> {}: """Download the post referenced by an announce """ if not postJsonObject.get('object'): @@ -3891,6 +3911,10 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str, announceCacheDir = baseDir + '/cache/announce/' + nickname if not os.path.isdir(announceCacheDir): os.mkdir(announceCacheDir) + + postId = None + if postJsonObject.get('id'): + postId = postJsonObject['id'] announceFilename = \ announceCacheDir + '/' + \ postJsonObject['object'].replace('/', '#') + '.json' @@ -3951,43 +3975,65 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str, if not isinstance(announcedJson, dict): print('WARN: announce json is not a dict - ' + postJsonObject['object']) - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if not announcedJson.get('id'): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if '/statuses/' not in announcedJson['id']: - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if not hasUsersPath(announcedJson['id']): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if not announcedJson.get('type'): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if announcedJson['type'] != 'Note' and \ announcedJson['type'] != 'Article': # You can only announce Note or Article types - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if not announcedJson.get('content'): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if not announcedJson.get('published'): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if not validPostDate(announcedJson['published']): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None # Check the content of the announce contentStr = announcedJson['content'] if dangerousMarkup(contentStr, allowLocalNetworkAccess): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None if isFiltered(baseDir, nickname, domain, contentStr): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None # remove any long words @@ -4006,7 +4052,9 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str, announcedJson) if announcedJson['type'] != 'Create': # Create wrap failed - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None # labelAccusatoryPost(postJsonObject, translate) @@ -4022,7 +4070,9 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str, attributedDomain = getFullDomain(attributedDomain, attributedPort) if isBlocked(baseDir, nickname, domain, attributedNickname, attributedDomain): - _rejectAnnounce(announceFilename) + _rejectAnnounce(announceFilename, + baseDir, nickname, domain, postId, + recentPostsCache) return None postJsonObject = announcedJson replaceYouTube(postJsonObject, YTReplacementDomain) diff --git a/translations/ar.json b/translations/ar.json index 35b5ab3c3..872bb6f69 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -387,5 +387,14 @@ "She/Her": "هي", "girl": "فتاة", "boy": "صبي", - "pronoun": "ضمير" + "pronoun": "ضمير", + "Type of instance": "نوع المثيل", + "Security": "حماية", + "Enabling broch mode": "يوفر تمكين وضع الكتيب تحصينًا مؤقتًا ضد الهجوم. لن يتم قبول سوى المشاركات من خلال المثيلات المعروفة بالفعل. تنقضي بعد أسبوع.", + "Instance Settings": "إعدادات المثيل", + "Video Settings": "اعدادات الفيديو", + "Filtering and Blocking": "التصفية والحظر", + "Role Assignment": "تعيين الدور", + "Contact Details": "بيانات المتصل", + "Background Images": "صور الخلفية" } diff --git a/translations/ca.json b/translations/ca.json index 52dde7634..05fd736f3 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -387,5 +387,14 @@ "She/Her": "Ella", "girl": "noia", "boy": "noi", - "pronoun": "pronom" + "pronoun": "pronom", + "Type of instance": "Tipus d’instància", + "Security": "Seguretat", + "Enabling broch mode": "L'activació del mode de fulletó proporciona una fortificació temporal contra l'atac. Només s’acceptaran publicacions d’instàncies ja conegudes. Transcorre al cap d’una setmana.", + "Instance Settings": "Configuració de la instància", + "Video Settings": "Configuració del vídeo", + "Filtering and Blocking": "Filtratge i bloqueig", + "Role Assignment": "Assignació de funcions", + "Contact Details": "Detalls de contacte", + "Background Images": "Imatges de fons" } diff --git a/translations/cy.json b/translations/cy.json index 54dd36563..43bc66b67 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -387,5 +387,14 @@ "She/Her": "Hi/Ei", "girl": "merch", "boy": "bachgen", - "pronoun": "rhagenw" + "pronoun": "rhagenw", + "Type of instance": "Math o enghraifft", + "Security": "Diogelwch", + "Enabling broch mode": "Mae modd galluogi broch yn darparu amddiffynfa dros dro yn erbyn ymosodiad. Dim ond swyddi mewn achosion y gwyddys amdanynt eisoes a dderbynnir. Mae'n mynd heibio ar ôl wythnos.", + "Instance Settings": "Gosodiadau Instance", + "Video Settings": "Gosodiadau Fideo", + "Filtering and Blocking": "Hidlo a Blocio", + "Role Assignment": "Aseiniad Rôl", + "Background Images": "Delweddau Cefndir", + "Contact Details": "Manylion cyswllt" } diff --git a/translations/de.json b/translations/de.json index 91cbcf5d2..a7e2e6d87 100644 --- a/translations/de.json +++ b/translations/de.json @@ -387,5 +387,14 @@ "She/Her": "Sie", "girl": "mädchen", "boy": "junge", - "pronoun": "pronomen" + "pronoun": "pronomen", + "Type of instance": "Art der Instanz", + "Security": "Sicherheit", + "Enabling broch mode": "Das Aktivieren des Broch-Modus bietet eine vorübergehende Verstärkung gegen Angriffe. Es werden nur Beiträge von bereits bekannten Instanzen akzeptiert. Es vergeht nach einer Woche.", + "Instance Settings": "Instanzeinstellungen", + "Video Settings": "Video-Einstellungen", + "Filtering and Blocking": "Filtern und Blockieren", + "Role Assignment": "Rollenzuweisung", + "Background Images": "Hintergrundbilder", + "Contact Details": "Kontaktdetails" } diff --git a/translations/en.json b/translations/en.json index e4c98b58a..1f5f1a1de 100644 --- a/translations/en.json +++ b/translations/en.json @@ -111,7 +111,7 @@ "Profile for": "Profile for", "The files attached below should be no larger than 10MB in total uploaded at once.": "The files attached below should be no larger than 10MB in total uploaded at once.", "Avatar image": "Avatar image", - "Background image": "Background image", + "Background image": "Background image, which appears behind your avatar", "Timeline banner image": "Timeline banner image", "Approve follower requests": "Approve follower requests", "This is a bot account": "This is a bot account", @@ -360,7 +360,7 @@ "New account": "New account", "Moved to new account address": "Moved to new account address", "Yet another Epicyon Instance": "Yet another Epicyon Instance", - "Other accounts": "Other accounts", + "Other accounts": "Other fediverse accounts", "Pin this post to your profile.": "Pin this post to your profile.", "Administered by": "Administered by", "Version": "Version", @@ -387,5 +387,14 @@ "She/Her": "She/Her", "girl": "girl", "boy": "boy", - "pronoun": "pronoun" + "pronoun": "pronoun", + "Type of instance": "Type of instance", + "Security": "Security", + "Enabling broch mode": "Enabling broch mode provides a temporary fortification against attack. Only posts by already known instances will be accepted. If not turned off, it elapses after a week.", + "Instance Settings": "Instance Settings", + "Video Settings": "Video Settings", + "Filtering and Blocking": "Filtering and Blocking", + "Role Assignment": "Role Assignment", + "Contact Details": "Contact Details", + "Background Images": "Background Images" } diff --git a/translations/es.json b/translations/es.json index e03be97ab..9414179e0 100644 --- a/translations/es.json +++ b/translations/es.json @@ -387,5 +387,14 @@ "She/Her": "Ella", "girl": "muchacha", "boy": "niño", - "pronoun": "pronombre" + "pronoun": "pronombre", + "Type of instance": "Tipo de instancia", + "Security": "Seguridad", + "Enabling broch mode": "Habilitar el modo broche proporciona una fortificación temporal contra el ataque. Solo se aceptarán publicaciones de instancias ya conocidas. Transcurre después de una semana.", + "Instance Settings": "Configuración de instancia", + "Video Settings": "Ajustes de video", + "Filtering and Blocking": "Filtrado y bloqueo", + "Role Assignment": "Asignación de roles", + "Background Images": "Imágenes de fondo", + "Contact Details": "Detalles de contacto" } diff --git a/translations/fr.json b/translations/fr.json index 91e3c6691..3aba51267 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -387,5 +387,14 @@ "She/Her": "Elle", "girl": "fille", "boy": "garçon", - "pronoun": "pronom" + "pronoun": "pronom", + "Type of instance": "Type d'instance", + "Security": "Sécurité", + "Enabling broch mode": "L'activation du mode broch fournit une fortification temporaire contre les attaques. Seuls les messages par des instances déjà connues seront acceptés. Il s'écoule après une semaine.", + "Instance Settings": "Paramètres d'instance", + "Video Settings": "Paramètres vidéo", + "Filtering and Blocking": "Filtrage et blocage", + "Role Assignment": "Attribution de rôle", + "Background Images": "Images d'arrière-plan", + "Contact Details": "Détails du contact" } diff --git a/translations/ga.json b/translations/ga.json index a50b84c60..cb98b3e88 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -387,5 +387,14 @@ "She/Her": "Sí", "girl": "cailín", "boy": "buachaill", - "pronoun": "forainm" + "pronoun": "forainm", + "Type of instance": "Cineál mar shampla", + "Security": "Slándáil", + "Enabling broch mode": "Soláthraíonn modh bróiste cumasaithe daingniú sealadach ar ionsaí. Ní ghlacfar ach le poist de réir cásanna a bhfuil eolas orthu cheana. Maireann sé tar éis seachtaine.", + "Instance Settings": "Socruithe Institiúide", + "Video Settings": "Socruithe Físe", + "Filtering and Blocking": "Scagadh agus Blocáil", + "Role Assignment": "Sannadh Róil", + "Background Images": "Íomhánna Cúlra", + "Contact Details": "Sonraí Teagmhála" } diff --git a/translations/hi.json b/translations/hi.json index e47922125..d890c16ba 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -387,5 +387,14 @@ "She/Her": "वह/उसकी", "girl": "लड़की", "boy": "लड़का", - "pronoun": "सवर्नाम" + "pronoun": "सवर्नाम", + "Type of instance": "उदाहरण के प्रकार", + "Security": "सुरक्षा", + "Enabling broch mode": "ब्रोश मोड को सक्षम करना हमले के खिलाफ एक अस्थायी किलेबंदी प्रदान करता है। केवल पहले से ज्ञात उदाहरणों द्वारा पोस्ट स्वीकार किए जाएंगे। यह एक सप्ताह के बाद समाप्त हो जाता है।", + "Instance Settings": "उदाहरण सेटिंग्स", + "Video Settings": "वीडियो सेटिंग्स", + "Filtering and Blocking": "छानना और अवरुद्ध करना", + "Role Assignment": "भूमिका असाइनमेंट", + "Background Images": "पृष्ठभूमि छवियों", + "Contact Details": "सम्पर्क करने का विवरण" } diff --git a/translations/it.json b/translations/it.json index bae879d33..be3e43443 100644 --- a/translations/it.json +++ b/translations/it.json @@ -387,5 +387,14 @@ "She/Her": "Lei", "girl": "ragazza", "boy": "ragazzo", - "pronoun": "pronome" + "pronoun": "pronome", + "Type of instance": "Tipo di istanza", + "Security": "Sicurezza", + "Enabling broch mode": "L'attivazione della modalità Broch fornisce una fortificazione temporanea contro gli attacchi. Verranno accettati solo i post di istanze già note. Scade dopo una settimana.", + "Instance Settings": "Impostazioni istanza", + "Video Settings": "Impostazioni video", + "Filtering and Blocking": "Filtraggio e blocco", + "Role Assignment": "Assegnazione del ruolo", + "Background Images": "Immagini di sfondo", + "Contact Details": "Dettagli del contatto" } diff --git a/translations/ja.json b/translations/ja.json index 441a5fa7d..d5ef7d006 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -387,5 +387,14 @@ "She/Her": "彼女", "girl": "女の子", "boy": "男の子", - "pronoun": "代名詞" + "pronoun": "代名詞", + "Type of instance": "インスタンスのタイプ", + "Security": "セキュリティ", + "Enabling broch mode": "ブロッホモードを有効にすると、攻撃に対する一時的な要塞が提供されます。 既知のインスタンスによる投稿のみが受け入れられます。 一週間後に経過します。", + "Instance Settings": "インスタンス設定", + "Video Settings": "ビデオ設定", + "Filtering and Blocking": "フィルタリングとブロッキング", + "Role Assignment": "役割の割り当て", + "Background Images": "背景画像", + "Contact Details": "連絡先の詳細" } diff --git a/translations/oc.json b/translations/oc.json index bf8bac91f..f8495c139 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -356,7 +356,7 @@ "New account": "New account", "Moved to new account address": "Moved to new account address", "Yet another Epicyon Instance": "Yet another Epicyon Instance", - "Other accounts": "Other accounts", + "Other accounts": "Other fediverse accounts", "Pin this post to your profile.": "Pin this post to your profile.", "Administered by": "Administered by", "Version": "Version", @@ -383,5 +383,14 @@ "She/Her": "She/Her", "girl": "girl", "boy": "boy", - "pronoun": "pronoun" + "pronoun": "pronoun", + "Type of instance": "Type of instance", + "Security": "Security", + "Enabling broch mode": "Enabling broch mode provides a temporary fortification against attack. Only posts by already known instances will be accepted. If not turned off, it elapses after a week.", + "Instance Settings": "Instance Settings", + "Video Settings": "Video Settings", + "Filtering and Blocking": "Filtering and Blocking", + "Role Assignment": "Role Assignment", + "Background Images": "Background Images", + "Contact Details": "Contact Details" } diff --git a/translations/pt.json b/translations/pt.json index b5a5ff75f..54ffea0d8 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -387,5 +387,14 @@ "She/Her": "Ela", "girl": "garota", "boy": "garoto", - "pronoun": "pronome" + "pronoun": "pronome", + "Type of instance": "Tipo de instância", + "Security": "Segurança", + "Enabling broch mode": "Habilitar o modo broch fornece uma fortificação temporária contra ataques. Somente postagens de instâncias já conhecidas serão aceitas. Decorre depois de uma semana.", + "Instance Settings": "Configurações de instância", + "Video Settings": "Configurações de vídeo", + "Filtering and Blocking": "Filtragem e Bloqueio", + "Role Assignment": "Atribuição de Função", + "Background Images": "Imagens de fundo", + "Contact Details": "Detalhes do contato" } diff --git a/translations/ru.json b/translations/ru.json index d90360b34..f171d543c 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -387,5 +387,14 @@ "She/Her": "Она/Ее", "girl": "девочка", "boy": "мальчик", - "pronoun": "местоимение" + "pronoun": "местоимение", + "Type of instance": "Тип экземпляра", + "Security": "Безопасность", + "Enabling broch mode": "Включение режима брошюры обеспечивает временную защиту от атак. Будут приниматься только сообщения от уже известных экземпляров. Проходит через неделю.", + "Instance Settings": "Настройки экземпляра", + "Video Settings": "Настройки видео", + "Filtering and Blocking": "Фильтрация и блокировка", + "Role Assignment": "Назначение ролей", + "Background Images": "Фоновые изображения", + "Contact Details": "Контактная информация" } diff --git a/translations/zh.json b/translations/zh.json index 8b88da848..493e6e184 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -387,5 +387,14 @@ "She/Her": "她", "girl": "女孩", "boy": "男生", - "pronoun": "代词" + "pronoun": "代词", + "Type of instance": "实例类型", + "Security": "安全", + "Enabling broch mode": "启用broch模式可提供针对攻击的临时防御。 仅接受已知实例的帖子。 一个星期后就过去了。", + "Instance Settings": "实例设定", + "Video Settings": "影片设定", + "Filtering and Blocking": "过滤和阻止", + "Role Assignment": "角色分配", + "Background Images": "背景图片", + "Contact Details": "联系方式" } diff --git a/utils.py b/utils.py index cad02295d..57d41662f 100644 --- a/utils.py +++ b/utils.py @@ -100,7 +100,7 @@ def hasUsersPath(pathStr: str) -> bool: return False -def validPostDate(published: str, maxAgeDays=7) -> bool: +def validPostDate(published: str, maxAgeDays=90) -> bool: """Returns true if the published date is recent and is not in the future """ baselineTime = datetime.datetime(1970, 1, 1) @@ -1206,7 +1206,7 @@ def deletePost(baseDir: str, httpPrefix: str, # remove any attachment _removeAttachment(baseDir, httpPrefix, domain, postJsonObject) - extensions = ('votes', 'arrived', 'muted', '.tts') + extensions = ('votes', 'arrived', 'muted', 'tts', 'reject') for ext in extensions: extFilename = postFilename + '.' + ext if os.path.isfile(extFilename): @@ -2034,3 +2034,37 @@ def camelCaseSplit(text: str) -> str: for word in matches: resultStr += word.group(0) + ' ' return resultStr.strip() + + +def rejectPostId(baseDir: str, nickname: str, domain: str, + postId: str, recentPostsCache: {}) -> None: + """ Marks the given post as rejected, + for example an announce which is too old + """ + postFilename = locatePost(baseDir, nickname, domain, postId) + if not postFilename: + return + + if recentPostsCache.get('index'): + # if this is a full path then remove the directories + indexFilename = postFilename + if '/' in postFilename: + indexFilename = postFilename.split('/')[-1] + + # filename of the post without any extension or path + # This should also correspond to any index entry in + # the posts cache + postUrl = \ + indexFilename.replace('\n', '').replace('\r', '') + postUrl = postUrl.replace('.json', '').strip() + + if postUrl in recentPostsCache['index']: + if recentPostsCache['json'].get(postUrl): + del recentPostsCache['json'][postUrl] + if recentPostsCache['html'].get(postUrl): + del recentPostsCache['html'][postUrl] + + rejectFile = open(postFilename + '.reject', "w+") + if rejectFile: + rejectFile.write('\n') + rejectFile.close() diff --git a/webapp_post.py b/webapp_post.py index c06c55959..532f535d2 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -22,6 +22,7 @@ from posts import getPersonBox from posts import isDM from posts import downloadAnnounce from posts import populateRepliesJson +from utils import rejectPostId from utils import isRecentPost from utils import getConfigParam from utils import getFullDomain @@ -1288,8 +1289,12 @@ def individualPostAsHtml(allowDownloads: bool, nickname, domain, postJsonObject, projectVersion, translate, YTReplacementDomain, - allowLocalNetworkAccess) + allowLocalNetworkAccess, + recentPostsCache) if not postJsonAnnounce: + # if the announce could not be downloaded then mark it as rejected + rejectPostId(baseDir, nickname, domain, postJsonObject['id'], + recentPostsCache) return '' postJsonObject = postJsonAnnounce diff --git a/webapp_profile.py b/webapp_profile.py index 4a1dff572..b5398be0d 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -1211,26 +1211,30 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str, '

' + skillsStr += ' \n' cssFilename = baseDir + '/epicyon-profile.css' if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - moderatorsStr = '' themesDropdown = '' instanceStr = '' - editorsStr = '' + roleAssignStr = '' peertubeStr = '' adminNickname = getConfigParam(baseDir, 'admin') if adminNickname: if path.startswith('/users/' + adminNickname + '/'): + # Instance details section instanceDescription = \ getConfigParam(baseDir, 'instanceDescription') instanceDescriptionShort = \ getConfigParam(baseDir, 'instanceDescriptionShort') instanceTitle = \ getConfigParam(baseDir, 'instanceTitle') + + instanceStr = '
' + \ + translate['Instance Settings'] + '\n' instanceStr += '
' instanceStr += \ ' ' instanceStr += \ ' ' - if getConfigParam(baseDir, "verifyAllSignatures"): - instanceStr += \ - ' ' + \ - translate['Verify all signatures'] + '
\n' - else: - instanceStr += \ - ' ' + \ - translate['Verify all signatures'] + '
\n' - if getConfigParam(baseDir, "brochMode"): - instanceStr += \ - ' ' + \ - translate['Broch mode'] + '
\n' - else: - instanceStr += \ - ' ' + \ - translate['Broch mode'] + '
\n' - instanceStr += '
' - - moderators = '' - moderatorsFile = baseDir + '/accounts/moderators.txt' - if os.path.isfile(moderatorsFile): - with open(moderatorsFile, "r") as f: - moderators = f.read() - moderatorsStr = '
' - moderatorsStr += ' ' + translate['Moderators'] + '
' - moderatorsStr += ' ' + \ - translate['A list of moderator nicknames. One per line.'] - moderatorsStr += \ - ' ' - moderatorsStr += '
' - - editors = '' - editorsFile = baseDir + '/accounts/editors.txt' - if os.path.isfile(editorsFile): - with open(editorsFile, "r") as f: - editors = f.read() - editorsStr = '
' - editorsStr += ' ' + translate['Site Editors'] + '
' - editorsStr += ' ' + \ - translate['A list of editor nicknames. One per line.'] - editorsStr += \ - ' ' - editorsStr += '
' + instanceStr += ' accept="' + imageFormats + '">
\n' + # Themes section themes = getThemesList(baseDir) - themesDropdown = '
' - themesDropdown += ' ' + translate['Theme'] + '
' + themesDropdown += '

\n' grayscaleFilename = \ baseDir + '/accounts/.grayscale' grayscale = '' @@ -1352,15 +1305,96 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str, ' ' + \ translate['Remove the custom font'] + '
' - themesDropdown += '
' themeName = getConfigParam(baseDir, 'theme') themesDropdown = \ themesDropdown.replace('
\n' - peertubeStr = \ - '